summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/ac.c33
-rw-r--r--drivers/acpi/acpi_lpss.c26
-rw-r--r--drivers/acpi/apei/cper.c18
-rw-r--r--drivers/acpi/apei/ghes.c11
-rw-r--r--drivers/acpi/csrt.c159
-rw-r--r--drivers/acpi/device_pm.c136
-rw-r--r--drivers/acpi/ec.c4
-rw-r--r--drivers/acpi/internal.h1
-rw-r--r--drivers/acpi/pci_root.c4
-rw-r--r--drivers/acpi/processor_driver.c8
-rw-r--r--drivers/acpi/processor_idle.c29
-rw-r--r--drivers/acpi/scan.c9
-rw-r--r--drivers/acpi/video.c27
-rw-r--r--drivers/acpi/video_detect.c8
-rw-r--r--drivers/ata/acard-ahci.c2
-rw-r--r--drivers/ata/ahci.c4
-rw-r--r--drivers/ata/ahci.h2
-rw-r--r--drivers/ata/ata_piix.c17
-rw-r--r--drivers/ata/libahci.c2
-rw-r--r--drivers/ata/libata-core.c8
-rw-r--r--drivers/ata/libata-eh.c2
-rw-r--r--drivers/ata/libata-scsi.c2
-rw-r--r--drivers/ata/libata-sff.c2
-rw-r--r--drivers/ata/pata_ep93xx.c5
-rw-r--r--drivers/ata/pdc_adma.c2
-rw-r--r--drivers/ata/sata_promise.c2
-rw-r--r--drivers/ata/sata_rcar.c24
-rw-r--r--drivers/ata/sata_sil.c2
-rw-r--r--drivers/ata/sata_sx4.c2
-rw-r--r--drivers/ata/sata_via.c2
-rw-r--r--drivers/atm/ambassador.c2
-rw-r--r--drivers/base/bus.c1
-rw-r--r--drivers/base/core.c6
-rw-r--r--drivers/base/power/common.c12
-rw-r--r--drivers/base/regmap/regcache-rbtree.c6
-rw-r--r--drivers/base/regmap/regcache.c20
-rw-r--r--drivers/base/regmap/regmap-debugfs.c5
-rw-r--r--drivers/block/brd.c4
-rw-r--r--drivers/block/cciss.c32
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c8
-rw-r--r--drivers/block/nvme-core.c62
-rw-r--r--drivers/block/nvme-scsi.c3
-rw-r--r--drivers/block/pktcdvd.c3
-rw-r--r--drivers/block/rbd.c968
-rw-r--r--drivers/block/xsysace.c3
-rw-r--r--drivers/char/hw_random/mxc-rnga.c6
-rw-r--r--drivers/char/hw_random/omap-rng.c5
-rw-r--r--drivers/char/ipmi/ipmi_bt_sm.c4
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c14
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c3
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c16
-rw-r--r--drivers/char/lp.c3
-rw-r--r--drivers/char/random.c54
-rw-r--r--drivers/char/ttyprintk.c2
-rw-r--r--drivers/clk/clk-si5351.c12
-rw-r--r--drivers/clk/clk-vt8500.c2
-rw-r--r--drivers/clk/mxs/clk-imx28.c1
-rw-r--r--drivers/clk/samsung/clk-exynos4.c6
-rw-r--r--drivers/clk/tegra/clk-tegra20.c11
-rw-r--r--drivers/clk/ux500/clk-sysctrl.c8
-rw-r--r--drivers/clk/ux500/u8500_clk.c2
-rw-r--r--drivers/clk/x86/clk-lpt.c15
-rw-r--r--drivers/cpufreq/Kconfig2
-rw-r--r--drivers/cpufreq/Kconfig.arm15
-rw-r--r--drivers/cpufreq/Kconfig.x862
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c4
-rw-r--r--drivers/cpufreq/arm_big_little.c7
-rw-r--r--drivers/cpufreq/arm_big_little.h5
-rw-r--r--drivers/cpufreq/arm_big_little_dt.c94
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c32
-rw-r--r--drivers/cpufreq/cpufreq.c19
-rw-r--r--drivers/cpufreq/cpufreq_governor.c14
-rw-r--r--drivers/cpufreq/cpufreq_governor.h1
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c1
-rw-r--r--drivers/cpufreq/cpufreq_stats.c7
-rw-r--r--drivers/cpufreq/intel_pstate.c123
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c4
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c2
-rw-r--r--drivers/crypto/caam/caamalg.c4
-rw-r--r--drivers/crypto/nx/nx-aes-cbc.c1
-rw-r--r--drivers/crypto/nx/nx-aes-ecb.c1
-rw-r--r--drivers/crypto/nx/nx-aes-gcm.c2
-rw-r--r--drivers/crypto/nx/nx-sha256.c8
-rw-r--r--drivers/crypto/nx/nx-sha512.c7
-rw-r--r--drivers/crypto/nx/nx.c38
-rw-r--r--drivers/crypto/sahara.c2
-rw-r--r--drivers/dma/acpi-dma.c172
-rw-r--r--drivers/dma/dmatest.c45
-rw-r--r--drivers/dma/ste_dma40.c8
-rw-r--r--drivers/dma/tegra20-apb-dma.c5
-rw-r--r--drivers/edac/amd64_edac_inj.c4
-rw-r--r--drivers/firmware/efi/efivars.c8
-rw-r--r--drivers/gpio/Kconfig2
-rw-r--r--drivers/gpio/gpio-langwell.c17
-rw-r--r--drivers/gpio/gpio-ml-ioh.c3
-rw-r--r--drivers/gpio/gpio-mvebu.c5
-rw-r--r--drivers/gpio/gpio-mxs.c3
-rw-r--r--drivers/gpio/gpio-omap.c48
-rw-r--r--drivers/gpio/gpio-pch.c3
-rw-r--r--drivers/gpio/gpio-sch.c6
-rw-r--r--drivers/gpio/gpio-tegra.c5
-rw-r--r--drivers/gpio/gpio-viperboard.c3
-rw-r--r--drivers/gpu/drm/drm_crtc.c5
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c27
-rw-r--r--drivers/gpu/drm/drm_drv.c20
-rw-r--r--drivers/gpu/drm/drm_encoder_slave.c6
-rw-r--r--drivers/gpu/drm/drm_irq.c6
-rw-r--r--drivers/gpu/drm/drm_mm.c34
-rw-r--r--drivers/gpu/drm/drm_modes.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c27
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c18
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c13
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c26
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c14
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_display.c30
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c4
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.c33
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c46
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h15
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c17
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c15
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h2
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c5
-rw-r--r--drivers/gpu/drm/i915/intel_display.c54
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c79
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h1
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c16
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c5
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c4
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c44
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c26
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c99
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nvc0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c14
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/class.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/init.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c13
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c25
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c3
-rw-r--r--drivers/gpu/drm/qxl/Kconfig1
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c29
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c17
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h7
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c5
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c9
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c6
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c11
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c51
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c7
-rw-r--r--drivers/gpu/drm/radeon/ni.c10
-rw-r--r--drivers/gpu/drm/radeon/r100.c9
-rw-r--r--drivers/gpu/drm/radeon/r300.c9
-rw-r--r--drivers/gpu/drm/radeon/r300_cmdbuf.c2
-rw-r--r--drivers/gpu/drm/radeon/r420.c10
-rw-r--r--drivers/gpu/drm/radeon/r520.c9
-rw-r--r--drivers/gpu/drm/radeon/r600.c62
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c9
-rw-r--r--drivers/gpu/drm/radeon/r600d.h8
-rw-r--r--drivers/gpu/drm/radeon/radeon.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c26
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c28
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c28
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c13
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_family.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c2
-rw-r--r--drivers/gpu/drm/radeon/rs400.c9
-rw-r--r--drivers/gpu/drm/radeon/rs600.c9
-rw-r--r--drivers/gpu/drm/radeon/rs690.c9
-rw-r--r--drivers/gpu/drm/radeon/rv515.c9
-rw-r--r--drivers/gpu/drm/radeon/rv770.c23
-rw-r--r--drivers/gpu/drm/radeon/si.c382
-rw-r--r--drivers/gpu/drm/radeon/sid.h1
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_crtc.c19
-rw-r--r--drivers/gpu/drm/tilcdc/Kconfig1
-rw-r--r--drivers/gpu/host1x/drm/dc.c5
-rw-r--r--drivers/hid/hid-multitouch.c11
-rw-r--r--drivers/hv/channel_mgmt.c2
-rw-r--r--drivers/hwmon/abituguru.c16
-rw-r--r--drivers/hwmon/adm1021.c58
-rw-r--r--drivers/hwmon/iio_hwmon.c8
-rw-r--r--drivers/hwmon/nct6775.c6
-rw-r--r--drivers/hwmon/tmp401.c2
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c14
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h2
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c1
-rw-r--r--drivers/i2c/busses/i2c-i801.c6
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c8
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c5
-rw-r--r--drivers/i2c/busses/i2c-sirf.c6
-rw-r--r--drivers/i2c/busses/i2c-tegra.c5
-rw-r--r--drivers/i2c/i2c-core.c3
-rw-r--r--drivers/iio/adc/exynos_adc.c8
-rw-r--r--drivers/iio/buffer_cb.c5
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_core.c2
-rw-r--r--drivers/iio/dac/Kconfig6
-rw-r--r--drivers/iio/frequency/adf4350.c2
-rw-r--r--drivers/iio/inkern.c4
-rw-r--r--drivers/infiniband/core/cma.c4
-rw-r--r--drivers/infiniband/hw/mlx4/main.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_keys.c2
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c1
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h1
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c1
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c1
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c16
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c34
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.h1
-rw-r--r--drivers/input/mouse/synaptics.c2
-rw-r--r--drivers/input/tablet/wacom_wac.c95
-rw-r--r--drivers/input/tablet/wacom_wac.h1
-rw-r--r--drivers/input/touchscreen/egalax_ts.c2
-rw-r--r--drivers/irqchip/irq-mxs.c14
-rw-r--r--drivers/irqchip/irq-versatile-fpga.c2
-rw-r--r--drivers/irqchip/irq-vic.c2
-rw-r--r--drivers/isdn/capi/kcapi.c6
-rw-r--r--drivers/isdn/i4l/isdn_net.c2
-rw-r--r--drivers/leds/leds-gpio.c9
-rw-r--r--drivers/leds/leds-ot200.c14
-rw-r--r--drivers/lguest/page_tables.c1
-rw-r--r--drivers/md/bcache/Kconfig1
-rw-r--r--drivers/md/bcache/bcache.h2
-rw-r--r--drivers/md/bcache/stats.c34
-rw-r--r--drivers/md/bcache/super.c185
-rw-r--r--drivers/md/bcache/writeback.c2
-rw-r--r--drivers/md/dm-thin.c4
-rw-r--r--drivers/md/md.c2
-rw-r--r--drivers/md/raid1.c38
-rw-r--r--drivers/md/raid10.c29
-rw-r--r--drivers/md/raid5.c6
-rw-r--r--drivers/media/pci/zoran/zoran.h2
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c15
-rw-r--r--drivers/media/platform/omap/omap_vout.c3
-rw-r--r--drivers/memory/emif.c6
-rw-r--r--drivers/mfd/Kconfig3
-rw-r--r--drivers/mfd/ab8500-core.c24
-rw-r--r--drivers/mfd/ab8500-debugfs.c16
-rw-r--r--drivers/mfd/ab8500-gpadc.c7
-rw-r--r--drivers/mfd/ab8500-sysctrl.c15
-rw-r--r--drivers/mfd/abx500-core.c2
-rw-r--r--drivers/mfd/cros_ec_spi.c6
-rw-r--r--drivers/mfd/db8500-prcmu.c3
-rw-r--r--drivers/mfd/intel_msic.c5
-rw-r--r--drivers/mfd/si476x-cmd.c152
-rw-r--r--drivers/misc/atmel-ssc.c5
-rw-r--r--drivers/misc/dummy-irq.c6
-rw-r--r--drivers/misc/mei/bus.c2
-rw-r--r--drivers/misc/mei/init.c4
-rw-r--r--drivers/misc/mei/main.c17
-rw-r--r--drivers/misc/mei/nfc.c2
-rw-r--r--drivers/misc/mei/pci-me.c1
-rw-r--r--drivers/misc/sgi-gru/grufile.c1
-rw-r--r--drivers/misc/vmw_vmci/Kconfig2
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c2
-rw-r--r--drivers/mmc/host/atmel-mci.c25
-rw-r--r--drivers/mmc/host/mmci.c9
-rw-r--r--drivers/mmc/host/omap_hsmmc.c51
-rw-r--r--drivers/mmc/host/sdhci-acpi.c69
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c41
-rw-r--r--drivers/mmc/host/sdhci-pci.c54
-rw-r--r--drivers/mtd/nand/lpc32xx_mlc.c5
-rw-r--r--drivers/net/Kconfig10
-rw-r--r--drivers/net/bonding/bond_3ad.c21
-rw-r--r--drivers/net/bonding/bond_3ad.h2
-rw-r--r--drivers/net/bonding/bond_alb.c99
-rw-r--r--drivers/net/bonding/bond_main.c222
-rw-r--r--drivers/net/bonding/bond_procfs.c2
-rw-r--r--drivers/net/bonding/bond_sysfs.c27
-rw-r--r--drivers/net/bonding/bonding.h3
-rw-r--r--drivers/net/caif/Kconfig2
-rw-r--r--drivers/net/can/Kconfig5
-rw-r--r--drivers/net/can/at91_can.c4
-rw-r--r--drivers/net/can/bfin_can.c10
-rw-r--r--drivers/net/can/c_can/c_can_platform.c6
-rw-r--r--drivers/net/can/cc770/cc770_isa.c5
-rw-r--r--drivers/net/can/cc770/cc770_platform.c4
-rw-r--r--drivers/net/can/flexcan.c27
-rw-r--r--drivers/net/can/grcan.c12
-rw-r--r--drivers/net/can/janz-ican3.c2
-rw-r--r--drivers/net/can/led.c4
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c10
-rw-r--r--drivers/net/can/sja1000/sja1000_isa.c5
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c6
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c5
-rw-r--r--drivers/net/can/slcan.c2
-rw-r--r--drivers/net/can/softing/softing_main.c2
-rw-r--r--drivers/net/can/ti_hecc.c1
-rw-r--r--drivers/net/can/usb/esd_usb2.c127
-rw-r--r--drivers/net/can/usb/kvaser_usb.c64
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.c61
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.h1
-rw-r--r--drivers/net/can/usb/usb_8dev.c5
-rw-r--r--drivers/net/ethernet/3com/3c509.c19
-rw-r--r--drivers/net/ethernet/3com/3c59x.c57
-rw-r--r--drivers/net/ethernet/3com/Kconfig1
-rw-r--r--drivers/net/ethernet/8390/ne.c1
-rw-r--r--drivers/net/ethernet/Kconfig5
-rw-r--r--drivers/net/ethernet/Makefile1
-rw-r--r--drivers/net/ethernet/adaptec/Kconfig1
-rw-r--r--drivers/net/ethernet/adi/Kconfig1
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.c4
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c4
-rw-r--r--drivers/net/ethernet/allwinner/Kconfig35
-rw-r--r--drivers/net/ethernet/allwinner/Makefile5
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.c954
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.h108
-rw-r--r--drivers/net/ethernet/alteon/acenic.c15
-rw-r--r--drivers/net/ethernet/amd/Kconfig2
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c19
-rw-r--r--drivers/net/ethernet/amd/au1000_eth.c2
-rw-r--r--drivers/net/ethernet/amd/sunlance.c6
-rw-r--r--drivers/net/ethernet/apple/bmac.c4
-rw-r--r--drivers/net/ethernet/atheros/Kconfig22
-rw-r--r--drivers/net/ethernet/atheros/Makefile1
-rw-r--r--drivers/net/ethernet/atheros/alx/Makefile3
-rw-r--r--drivers/net/ethernet/atheros/alx/alx.h114
-rw-r--r--drivers/net/ethernet/atheros/alx/ethtool.c272
-rw-r--r--drivers/net/ethernet/atheros/alx/hw.c1226
-rw-r--r--drivers/net/ethernet/atheros/alx/hw.h499
-rw-r--r--drivers/net/ethernet/atheros/alx/main.c1625
-rw-r--r--drivers/net/ethernet/atheros/alx/reg.h810
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c25
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c25
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c27
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig2
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c1152
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.h86
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c18
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h183
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c220
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h75
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c52
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h7
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c100
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h5
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c670
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c284
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h55
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c36
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h5
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c21
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c2
-rw-r--r--drivers/net/ethernet/broadcom/sb1250-mac.c9
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c517
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs.h3
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bna.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_tx_rx.c15
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c8
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_debugfs.c2
-rw-r--r--drivers/net/ethernet/brocade/bna/cna.h4
-rw-r--r--drivers/net/ethernet/cadence/Kconfig4
-rw-r--r--drivers/net/ethernet/cadence/at91_ether.c1
-rw-r--r--drivers/net/ethernet/cadence/macb.c343
-rw-r--r--drivers/net/ethernet/cadence/macb.h21
-rw-r--r--drivers/net/ethernet/calxeda/Kconfig2
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/cxgb2.c15
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c9
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c116
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c27
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c10
-rw-r--r--drivers/net/ethernet/cirrus/Kconfig1
-rw-r--r--drivers/net/ethernet/cirrus/ep93xx_eth.c1
-rw-r--r--drivers/net/ethernet/davicom/Kconfig1
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c53
-rw-r--r--drivers/net/ethernet/dec/tulip/Kconfig1
-rw-r--r--drivers/net/ethernet/dec/tulip/interrupt.c6
-rw-r--r--drivers/net/ethernet/dec/tulip/tulip_core.c6
-rw-r--r--drivers/net/ethernet/dec/tulip/xircom_cb.c14
-rw-r--r--drivers/net/ethernet/dlink/Kconfig1
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h5
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c85
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h3
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c37
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h4
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c222
-rw-r--r--drivers/net/ethernet/ethoc.c2
-rw-r--r--drivers/net/ethernet/faraday/Kconfig1
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c2
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.c2
-rw-r--r--drivers/net/ethernet/freescale/fec.h3
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c122
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx.c9
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c3
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/Kconfig1
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c5
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c6
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-fec.c6
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c57
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ptp.c5
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c4
-rw-r--r--drivers/net/ethernet/freescale/xgmac_mdio.c4
-rw-r--r--drivers/net/ethernet/ibm/Kconfig3
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c4
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c36
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c6
-rw-r--r--drivers/net/ethernet/ibm/emac/rgmii.c18
-rw-r--r--drivers/net/ethernet/ibm/emac/tah.c14
-rw-r--r--drivers/net/ethernet/ibm/emac/zmii.c18
-rw-r--r--drivers/net/ethernet/icplus/Kconfig1
-rw-r--r--drivers/net/ethernet/icplus/ipg.c13
-rw-r--r--drivers/net/ethernet/icplus/ipg.h86
-rw-r--r--drivers/net/ethernet/intel/Kconfig1
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c24
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c30
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c34
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h34
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c62
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c55
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.c1
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c22
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c120
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_defines.h36
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_hw.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.h6
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.c45
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.c124
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.h20
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h14
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c74
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c9
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h134
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c23
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c40
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c69
-rw-r--r--drivers/net/ethernet/jme.c1
-rw-r--r--drivers/net/ethernet/korina.c6
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c206
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c46
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c3
-rw-r--r--drivers/net/ethernet/marvell/skge.c2
-rw-r--r--drivers/net/ethernet/marvell/sky2.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c50
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_cq.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c72
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_resources.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c15
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c22
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h133
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c29
-rw-r--r--drivers/net/ethernet/micrel/Kconfig4
-rw-r--r--drivers/net/ethernet/micrel/ks8695net.c1
-rw-r--r--drivers/net/ethernet/micrel/ks8842.c1
-rw-r--r--drivers/net/ethernet/micrel/ks8851_mll.c34
-rw-r--r--drivers/net/ethernet/netx-eth.c5
-rw-r--r--drivers/net/ethernet/nuvoton/Kconfig1
-rw-r--r--drivers/net/ethernet/nuvoton/w90p910_ether.c2
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c17
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c2
-rw-r--r--drivers/net/ethernet/octeon/octeon_mgmt.c4
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/Kconfig1
-rw-r--r--drivers/net/ethernet/packetengines/Kconfig1
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic.h14
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h3
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c133
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h35
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c172
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c59
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c39
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c45
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c54
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c64
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c197
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h2
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c16
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c39
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c129
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c21
-rw-r--r--drivers/net/ethernet/rdc/Kconfig1
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c1
-rw-r--r--drivers/net/ethernet/realtek/Kconfig3
-rw-r--r--drivers/net/ethernet/realtek/r8169.c41
-rw-r--r--drivers/net/ethernet/renesas/Kconfig7
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c539
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.h29
-rw-r--r--drivers/net/ethernet/s6gmac.c1
-rw-r--r--drivers/net/ethernet/seeq/sgiseeq.c1
-rw-r--r--drivers/net/ethernet/sfc/efx.c10
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h34
-rw-r--r--drivers/net/ethernet/sfc/rx.c8
-rw-r--r--drivers/net/ethernet/sfc/siena.c2
-rw-r--r--drivers/net/ethernet/sgi/Kconfig1
-rw-r--r--drivers/net/ethernet/sgi/ioc3-eth.c14
-rw-r--r--drivers/net/ethernet/sgi/meth.c1
-rw-r--r--drivers/net/ethernet/silan/sc92031.c14
-rw-r--r--drivers/net/ethernet/sis/Kconfig2
-rw-r--r--drivers/net/ethernet/sis/sis190.c13
-rw-r--r--drivers/net/ethernet/smsc/Kconfig7
-rw-r--r--drivers/net/ethernet/smsc/smc911x.c2
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c3
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c2
-rw-r--r--drivers/net/ethernet/sun/niu.c5
-rw-r--r--drivers/net/ethernet/sun/sunbmac.c5
-rw-r--r--drivers/net/ethernet/sun/sungem.c13
-rw-r--r--drivers/net/ethernet/sun/sunhme.c4
-rw-r--r--drivers/net/ethernet/sun/sunqe.c10
-rw-r--r--drivers/net/ethernet/ti/cpsw.c5
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c5
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c2
-rw-r--r--drivers/net/ethernet/ti/davinci_mdio.c14
-rw-r--r--drivers/net/ethernet/ti/tlan.c1
-rw-r--r--drivers/net/ethernet/ti/tlan.h1
-rw-r--r--drivers/net/ethernet/toshiba/tc35815.c14
-rw-r--r--drivers/net/ethernet/tundra/tsi108_eth.c1
-rw-r--r--drivers/net/ethernet/via/Kconfig5
-rw-r--r--drivers/net/ethernet/via/via-velocity.c507
-rw-r--r--drivers/net/ethernet/via/via-velocity.h8
-rw-r--r--drivers/net/ethernet/wiznet/w5100.c2
-rw-r--r--drivers/net/ethernet/wiznet/w5300.c2
-rw-r--r--drivers/net/ethernet/xilinx/Kconfig4
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c5
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c6
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_emaclite.c239
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c2
-rw-r--r--drivers/net/fddi/skfp/skfddi.c13
-rw-r--r--drivers/net/hamradio/bpqether.c7
-rw-r--r--drivers/net/hippi/rrunner.c13
-rw-r--r--drivers/net/hyperv/netvsc_drv.c5
-rw-r--r--drivers/net/irda/bfin_sir.c1
-rw-r--r--drivers/net/irda/sh_irda.c1
-rw-r--r--drivers/net/irda/sh_sir.c1
-rw-r--r--drivers/net/macvlan.c29
-rw-r--r--drivers/net/macvtap.c212
-rw-r--r--drivers/net/netconsole.c5
-rw-r--r--drivers/net/ntb_netdev.c2
-rw-r--r--drivers/net/phy/Kconfig10
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/at803x.c128
-rw-r--r--drivers/net/phy/bcm63xx.c4
-rw-r--r--drivers/net/phy/marvell.c108
-rw-r--r--drivers/net/phy/mdio-sun4i.c194
-rw-r--r--drivers/net/phy/phy.c28
-rw-r--r--drivers/net/phy/phy_device.c11
-rw-r--r--drivers/net/phy/spi_ks8995.c14
-rw-r--r--drivers/net/phy/vitesse.c38
-rw-r--r--drivers/net/ppp/pppoe.c2
-rw-r--r--drivers/net/team/team.c95
-rw-r--r--drivers/net/team/team_mode_loadbalance.c3
-rw-r--r--drivers/net/team/team_mode_random.c2
-rw-r--r--drivers/net/team/team_mode_roundrobin.c5
-rw-r--r--drivers/net/tun.c20
-rw-r--r--drivers/net/usb/Kconfig4
-rw-r--r--drivers/net/usb/cdc_ether.c6
-rw-r--r--drivers/net/usb/kalmia.c45
-rw-r--r--drivers/net/usb/qmi_wwan.c2
-rw-r--r--drivers/net/usb/r8152.c14
-rw-r--r--drivers/net/usb/rtl8150.c100
-rw-r--r--drivers/net/usb/usbnet.c2
-rw-r--r--drivers/net/veth.c7
-rw-r--r--drivers/net/virtio_net.c11
-rw-r--r--drivers/net/vxlan.c361
-rw-r--r--drivers/net/wan/dlci.c2
-rw-r--r--drivers/net/wan/hdlc.c2
-rw-r--r--drivers/net/wan/ixp4xx_hss.c1
-rw-r--r--drivers/net/wan/lapbether.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_debug.c2
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c2
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c4
-rw-r--r--drivers/net/wireless/libertas/mesh.c2
-rw-r--r--drivers/net/wireless/rtlwifi/base.c2
-rw-r--r--drivers/net/xen-netback/common.h14
-rw-r--r--drivers/net/xen-netback/interface.c102
-rw-r--r--drivers/net/xen-netback/netback.c46
-rw-r--r--drivers/net/xen-netback/xenbus.c46
-rw-r--r--drivers/net/xen-netfront.c225
-rw-r--r--drivers/ntb/ntb_hw.c10
-rw-r--r--drivers/ntb/ntb_transport.c175
-rw-r--r--drivers/of/base.c19
-rw-r--r--drivers/of/of_net.c1
-rw-r--r--drivers/parisc/lba_pci.c9
-rw-r--r--drivers/parisc/superio.c13
-rw-r--r--drivers/parport/Kconfig2
-rw-r--r--drivers/parport/parport_gsc.c6
-rw-r--r--drivers/parport/parport_gsc.h2
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c14
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c5
-rw-r--r--drivers/pci/pcie/aer/aerdrv_errprint.c4
-rw-r--r--drivers/pinctrl/pinconf.c4
-rw-r--r--drivers/pinctrl/pinctrl-abx500.c30
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c8
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c139
-rw-r--r--drivers/pinctrl/pinctrl-exynos.h1
-rw-r--r--drivers/pinctrl/pinctrl-exynos5440.c5
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c3
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c159
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h9
-rw-r--r--drivers/pinctrl/pinctrl-single.c3
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c7
-rw-r--r--drivers/pinctrl/pinctrl-xway.c4
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7779.c45
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wm8750.c2
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c3
-rw-r--r--drivers/platform/x86/hp-wmi.c2
-rw-r--r--drivers/power/Kconfig2
-rw-r--r--drivers/power/pm2301_charger.c2
-rw-r--r--drivers/power/wm831x_backup.c1
-rw-r--r--drivers/ptp/ptp_pch.c8
-rw-r--r--drivers/pwm/pwm-imx.c5
-rw-r--r--drivers/pwm/pwm-puv3.c5
-rw-r--r--drivers/pwm/pwm-pxa.c5
-rw-r--r--drivers/pwm/pwm-tegra.c5
-rw-r--r--drivers/pwm/pwm-tiecap.c5
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c5
-rw-r--r--drivers/pwm/pwm-tipwmss.c5
-rw-r--r--drivers/pwm/pwm-vt8500.c5
-rw-r--r--drivers/rapidio/Kconfig20
-rw-r--r--drivers/rapidio/Makefile3
-rw-r--r--drivers/rapidio/devices/tsi721.c12
-rw-r--r--drivers/rapidio/rio-driver.c8
-rw-r--r--drivers/rapidio/rio-scan.c190
-rw-r--r--drivers/rapidio/rio-sysfs.c45
-rw-r--r--drivers/rapidio/rio.c246
-rw-r--r--drivers/rapidio/rio.h13
-rw-r--r--drivers/regulator/core.c7
-rw-r--r--drivers/regulator/dbx500-prcmu.c24
-rw-r--r--drivers/regulator/palmas-regulator.c4
-rw-r--r--drivers/rtc/Kconfig2
-rw-r--r--drivers/rtc/rtc-at91rm9200.c131
-rw-r--r--drivers/rtc/rtc-cmos.c4
-rw-r--r--drivers/rtc/rtc-max8998.c2
-rw-r--r--drivers/rtc/rtc-nuc900.c5
-rw-r--r--drivers/rtc/rtc-omap.c5
-rw-r--r--drivers/rtc/rtc-pl031.c2
-rw-r--r--drivers/rtc/rtc-s3c.c5
-rw-r--r--drivers/rtc/rtc-tegra.c6
-rw-r--r--drivers/rtc/rtc-tps6586x.c3
-rw-r--r--drivers/rtc/rtc-twl.c1
-rw-r--r--drivers/s390/block/dasd.c12
-rw-r--r--drivers/s390/block/xpram.c1
-rw-r--r--drivers/s390/cio/chp.c36
-rw-r--r--drivers/s390/cio/chsc.h4
-rw-r--r--drivers/s390/net/netiucv.c6
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c2
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c2
-rw-r--r--drivers/scsi/fcoe/fcoe.c2
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c2
-rw-r--r--drivers/scsi/fnic/fnic_debugfs.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c2
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c2
-rw-r--r--drivers/scsi/scsi_proc.c1
-rw-r--r--drivers/spi/spi-atmel.c51
-rw-r--r--drivers/spi/spi-davinci.c2
-rw-r--r--drivers/spi/spi-sh-hspi.c2
-rw-r--r--drivers/spi/spi-tegra20-sflash.c5
-rw-r--r--drivers/spi/spi-topcliff-pch.c3
-rw-r--r--drivers/spi/spi-xilinx.c74
-rw-r--r--drivers/spi/spi.c9
-rw-r--r--drivers/ssb/sprom.c2
-rw-r--r--drivers/staging/Kconfig4
-rw-r--r--drivers/staging/android/alarm-dev.c8
-rw-r--r--drivers/staging/android/logger.c4
-rw-r--r--drivers/staging/android/logger.h2
-rw-r--r--drivers/staging/comedi/Kconfig9
-rw-r--r--drivers/staging/comedi/comedi_buf.c12
-rw-r--r--drivers/staging/comedi/comedi_fops.c3
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c8
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.h1
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c20
-rw-r--r--drivers/staging/csr/netdev.c2
-rw-r--r--drivers/staging/dwc2/Kconfig2
-rw-r--r--drivers/staging/dwc2/hcd.c5
-rw-r--r--drivers/staging/dwc2/hcd_intr.c2
-rw-r--r--drivers/staging/dwc2/platform.c13
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c2
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_proc.c2
-rw-r--r--drivers/staging/gdm72xx/Kconfig2
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c5
-rw-r--r--drivers/staging/iio/light/tsl2x7x_core.c9
-rw-r--r--drivers/staging/imx-drm/Kconfig5
-rw-r--r--drivers/staging/imx-drm/imx-tve.c4
-rw-r--r--drivers/staging/imx-drm/ipuv3-crtc.c21
-rw-r--r--drivers/staging/media/solo6x10/Kconfig1
-rw-r--r--drivers/staging/nvec/nvec.c26
-rw-r--r--drivers/staging/nvec/nvec.h5
-rw-r--r--drivers/staging/nvec/nvec_kbd.c10
-rw-r--r--drivers/staging/nvec/nvec_power.c1
-rw-r--r--drivers/staging/nvec/nvec_ps2.c8
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c4
-rw-r--r--drivers/staging/sep/Kconfig2
-rw-r--r--drivers/staging/silicom/Kconfig7
-rw-r--r--drivers/staging/silicom/bpctl_mod.c2
-rw-r--r--drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c6
-rw-r--r--drivers/staging/vt6656/hostap.c2
-rw-r--r--drivers/staging/vt6656/iwctl.c6
-rw-r--r--drivers/staging/zcache/ramster.h4
-rw-r--r--drivers/staging/zcache/ramster/debug.c2
-rw-r--r--drivers/staging/zcache/ramster/ramster-howto.txt366
-rw-r--r--drivers/staging/zcache/ramster/ramster.c6
-rw-r--r--drivers/staging/zcache/zcache-main.c8
-rw-r--r--drivers/target/iscsi/iscsi_target.c75
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c7
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c12
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c16
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.h8
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c50
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h2
-rw-r--r--drivers/target/target_core_configfs.c11
-rw-r--r--drivers/target/target_core_device.c14
-rw-r--r--drivers/target/target_core_file.c18
-rw-r--r--drivers/target/target_core_iblock.c2
-rw-r--r--drivers/target/target_core_internal.h1
-rw-r--r--drivers/target/target_core_rd.c21
-rw-r--r--drivers/target/target_core_rd.h1
-rw-r--r--drivers/target/target_core_transport.c87
-rw-r--r--drivers/thermal/armada_thermal.c10
-rw-r--r--drivers/thermal/dove_thermal.c4
-rw-r--r--drivers/thermal/exynos_thermal.c5
-rw-r--r--drivers/tty/ehv_bytechan.c1
-rw-r--r--drivers/tty/mxser.c11
-rw-r--r--drivers/tty/n_tty.c8
-rw-r--r--drivers/tty/rocket.c288
-rw-r--r--drivers/tty/serial/8250/8250_core.c14
-rw-r--r--drivers/tty/serial/8250/8250_dw.c7
-rw-r--r--drivers/tty/serial/amba-pl011.c2
-rw-r--r--drivers/tty/serial/imx.c2
-rw-r--r--drivers/tty/serial/mcf.c4
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c11
-rw-r--r--drivers/tty/serial/nwpserial.c2
-rw-r--r--drivers/tty/serial/omap-serial.c23
-rw-r--r--drivers/tty/serial/samsung.c14
-rw-r--r--drivers/tty/vt/vt.c14
-rw-r--r--drivers/tty/vt/vt_ioctl.c67
-rw-r--r--drivers/uio/Kconfig1
-rw-r--r--drivers/usb/atm/cxacru.c3
-rw-r--r--drivers/usb/chipidea/Kconfig2
-rw-r--r--drivers/usb/chipidea/ci13xxx_imx.c15
-rw-r--r--drivers/usb/chipidea/core.c8
-rw-r--r--drivers/usb/chipidea/udc.c13
-rw-r--r--drivers/usb/core/Kconfig2
-rw-r--r--drivers/usb/core/devio.c10
-rw-r--r--drivers/usb/core/quirks.c3
-rw-r--r--drivers/usb/dwc3/Kconfig6
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c8
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c2
-rw-r--r--drivers/usb/dwc3/gadget.c16
-rw-r--r--drivers/usb/gadget/Kconfig1
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c2
-rw-r--r--drivers/usb/gadget/bcm63xx_udc.c11
-rw-r--r--drivers/usb/gadget/configfs.c8
-rw-r--r--drivers/usb/gadget/dummy_hcd.c5
-rw-r--r--drivers/usb/gadget/f_ecm.c1
-rw-r--r--drivers/usb/gadget/f_subset.c1
-rw-r--r--drivers/usb/gadget/f_uac2.c2
-rw-r--r--drivers/usb/gadget/fusb300_udc.c4
-rw-r--r--drivers/usb/gadget/imx_udc.c2
-rw-r--r--drivers/usb/gadget/m66592-udc.c4
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c1
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c4
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c2
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c3
-rw-r--r--drivers/usb/gadget/zero.c8
-rw-r--r--drivers/usb/host/Kconfig17
-rw-r--r--drivers/usb/host/ehci-atmel.c6
-rw-r--r--drivers/usb/host/ehci-hcd.c17
-rw-r--r--drivers/usb/host/ehci-omap.c8
-rw-r--r--drivers/usb/host/ehci-orion.c6
-rw-r--r--drivers/usb/host/ehci-s5p.c5
-rw-r--r--drivers/usb/host/ehci-sched.c9
-rw-r--r--drivers/usb/host/ehci-spear.c6
-rw-r--r--drivers/usb/host/ehci-tegra.c6
-rw-r--r--drivers/usb/host/isp1760-hcd.c2
-rw-r--r--drivers/usb/host/isp1760-if.c4
-rw-r--r--drivers/usb/host/ohci-at91.c6
-rw-r--r--drivers/usb/host/ohci-exynos.c4
-rw-r--r--drivers/usb/host/ohci-hcd.c34
-rw-r--r--drivers/usb/host/ohci-nxp.c50
-rw-r--r--drivers/usb/host/ohci-omap3.c8
-rw-r--r--drivers/usb/host/ohci-pxa27x.c6
-rw-r--r--drivers/usb/host/ohci-spear.c6
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c2
-rw-r--r--drivers/usb/host/sl811-hcd.c2
-rw-r--r--drivers/usb/host/uhci-hub.c3
-rw-r--r--drivers/usb/host/uhci-platform.c6
-rw-r--r--drivers/usb/host/uhci-q.c2
-rw-r--r--drivers/usb/host/xhci-mem.c27
-rw-r--r--drivers/usb/host/xhci-pci.c8
-rw-r--r--drivers/usb/host/xhci.c16
-rw-r--r--drivers/usb/host/xhci.h3
-rw-r--r--drivers/usb/musb/musb_dsps.c1
-rw-r--r--drivers/usb/musb/musb_host.c18
-rw-r--r--drivers/usb/musb/musb_host.h1
-rw-r--r--drivers/usb/musb/omap2430.c3
-rw-r--r--drivers/usb/phy/Kconfig5
-rw-r--r--drivers/usb/phy/phy-ab8500-usb.c2
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c1
-rw-r--r--drivers/usb/phy/phy-gpio-vbus-usb.c3
-rw-r--r--drivers/usb/phy/phy-isp1301.c1
-rw-r--r--drivers/usb/phy/phy-mv-u3d-usb.c5
-rw-r--r--drivers/usb/phy/phy-mv-usb.c3
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c8
-rw-r--r--drivers/usb/phy/phy-nop.c2
-rw-r--r--drivers/usb/phy/phy-samsung-usb2.c5
-rw-r--r--drivers/usb/phy/phy-samsung-usb3.c5
-rw-r--r--drivers/usb/serial/ark3116.c2
-rw-r--r--drivers/usb/serial/cypress_m8.c18
-rw-r--r--drivers/usb/serial/cypress_m8.h4
-rw-r--r--drivers/usb/serial/f81232.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.c30
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h2
-rw-r--r--drivers/usb/serial/generic.c31
-rw-r--r--drivers/usb/serial/io_ti.c22
-rw-r--r--drivers/usb/serial/iuu_phoenix.c4
-rw-r--r--drivers/usb/serial/keyspan.c10
-rw-r--r--drivers/usb/serial/mos7720.c25
-rw-r--r--drivers/usb/serial/mos7840.c35
-rw-r--r--drivers/usb/serial/option.c39
-rw-r--r--drivers/usb/serial/pl2303.c10
-rw-r--r--drivers/usb/serial/qcserial.c1
-rw-r--r--drivers/usb/serial/spcp8x5.c10
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c23
-rw-r--r--drivers/usb/serial/usb-serial.c34
-rw-r--r--drivers/usb/serial/visor.c9
-rw-r--r--drivers/usb/serial/whiteheat.c2
-rw-r--r--drivers/usb/serial/zte_ev.c58
-rw-r--r--drivers/usb/storage/realtek_cr.c8
-rw-r--r--drivers/vfio/vfio.c2
-rw-r--r--drivers/vhost/net.c29
-rw-r--r--drivers/vhost/vhost.c8
-rw-r--r--drivers/vhost/vhost.h1
-rw-r--r--drivers/vhost/vringh.c3
-rw-r--r--drivers/video/Kconfig19
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/atmel_lcdfb.c15
-rw-r--r--drivers/video/console/Makefile2
-rw-r--r--drivers/video/omap2/dss/core.c20
-rw-r--r--drivers/video/omap2/dss/hdmi.c4
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c3
-rw-r--r--drivers/video/omap2/vrfb.c5
-rw-r--r--drivers/video/ps3fb.c2
-rw-r--r--drivers/video/simplefb.c234
-rw-r--r--drivers/w1/masters/omap_hdq.c5
-rw-r--r--drivers/watchdog/ath79_wdt.c5
-rw-r--r--drivers/watchdog/davinci_wdt.c5
-rw-r--r--drivers/watchdog/imx2_wdt.c5
-rw-r--r--drivers/xen/Kconfig7
-rw-r--r--drivers/xen/balloon.c3
-rw-r--r--drivers/xen/privcmd.c2
-rw-r--r--drivers/xen/tmem.c93
-rw-r--r--drivers/xen/xen-pciback/pci_stub.c4
-rw-r--r--drivers/xen/xen-selfballoon.c47
-rw-r--r--drivers/xen/xenbus/xenbus_client.c5
-rw-r--r--drivers/xen/xenbus/xenbus_comms.h1
-rw-r--r--drivers/xen/xenbus/xenbus_dev_backend.c21
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c27
-rw-r--r--drivers/xen/xenbus/xenbus_probe.h7
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c37
892 files changed, 20199 insertions, 7910 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index ecb743b..536562c 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -24,7 +24,7 @@ acpi-y += nvs.o
# Power management related files
acpi-y += wakeup.o
acpi-y += sleep.o
-acpi-$(CONFIG_PM) += device_pm.o
+acpi-y += device_pm.o
acpi-$(CONFIG_ACPI_SLEEP) += proc.o
@@ -38,7 +38,6 @@ acpi-y += processor_core.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o
-acpi-y += csrt.o
acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o
acpi-y += acpi_platform.o
acpi-y += power.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 00d2efd..4f4e741 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -28,6 +28,8 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/dmi.h>
+#include <linux/delay.h>
#ifdef CONFIG_ACPI_PROCFS_POWER
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@@ -74,6 +76,8 @@ static int acpi_ac_resume(struct device *dev);
#endif
static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
+static int ac_sleep_before_get_state_ms;
+
static struct acpi_driver acpi_ac_driver = {
.name = "ac",
.class = ACPI_AC_CLASS,
@@ -252,6 +256,16 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
case ACPI_AC_NOTIFY_STATUS:
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
+ /*
+ * A buggy BIOS may notify AC first and then sleep for
+ * a specific time before doing actual operations in the
+ * EC event handler (_Qxx). This will cause the AC state
+ * reported by the ACPI event to be incorrect, so wait for a
+ * specific time for the EC event handler to make progress.
+ */
+ if (ac_sleep_before_get_state_ms > 0)
+ msleep(ac_sleep_before_get_state_ms);
+
acpi_ac_get_state(ac);
acpi_bus_generate_proc_event(device, event, (u32) ac->state);
acpi_bus_generate_netlink_event(device->pnp.device_class,
@@ -264,6 +278,24 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
return;
}
+static int thinkpad_e530_quirk(const struct dmi_system_id *d)
+{
+ ac_sleep_before_get_state_ms = 1000;
+ return 0;
+}
+
+static struct dmi_system_id ac_dmi_table[] = {
+ {
+ .callback = thinkpad_e530_quirk,
+ .ident = "thinkpad e530",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "32597CG"),
+ },
+ },
+ {},
+};
+
static int acpi_ac_add(struct acpi_device *device)
{
int result = 0;
@@ -312,6 +344,7 @@ static int acpi_ac_add(struct acpi_device *device)
kfree(ac);
}
+ dmi_check_system(ac_dmi_table);
return result;
}
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index b1c9542..652fd5c 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -35,11 +35,16 @@ ACPI_MODULE_NAME("acpi_lpss");
struct lpss_device_desc {
bool clk_required;
- const char *clk_parent;
+ const char *clkdev_name;
bool ltr_required;
unsigned int prv_offset;
};
+static struct lpss_device_desc lpss_dma_desc = {
+ .clk_required = true,
+ .clkdev_name = "hclk",
+};
+
struct lpss_private_data {
void __iomem *mmio_base;
resource_size_t mmio_size;
@@ -49,7 +54,6 @@ struct lpss_private_data {
static struct lpss_device_desc lpt_dev_desc = {
.clk_required = true,
- .clk_parent = "lpss_clk",
.prv_offset = 0x800,
.ltr_required = true,
};
@@ -60,6 +64,9 @@ static struct lpss_device_desc lpt_sdio_dev_desc = {
};
static const struct acpi_device_id acpi_lpss_device_ids[] = {
+ /* Generic LPSS devices */
+ { "INTL9C60", (unsigned long)&lpss_dma_desc },
+
/* Lynxpoint LPSS devices */
{ "INT33C0", (unsigned long)&lpt_dev_desc },
{ "INT33C1", (unsigned long)&lpt_dev_desc },
@@ -91,16 +98,27 @@ static int register_device_clock(struct acpi_device *adev,
struct lpss_private_data *pdata)
{
const struct lpss_device_desc *dev_desc = pdata->dev_desc;
+ struct lpss_clk_data *clk_data;
if (!lpss_clk_dev)
lpt_register_clock_device();
- if (!dev_desc->clk_parent || !pdata->mmio_base
+ clk_data = platform_get_drvdata(lpss_clk_dev);
+ if (!clk_data)
+ return -ENODEV;
+
+ if (dev_desc->clkdev_name) {
+ clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name,
+ dev_name(&adev->dev));
+ return 0;
+ }
+
+ if (!pdata->mmio_base
|| pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE)
return -ENODATA;
pdata->clk = clk_register_gate(NULL, dev_name(&adev->dev),
- dev_desc->clk_parent, 0,
+ clk_data->name, 0,
pdata->mmio_base + dev_desc->prv_offset,
0, 0, NULL);
if (IS_ERR(pdata->clk))
diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c
index fefc2ca..33dc6a0 100644
--- a/drivers/acpi/apei/cper.c
+++ b/drivers/acpi/apei/cper.c
@@ -250,10 +250,6 @@ static const char *cper_pcie_port_type_strs[] = {
static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
const struct acpi_hest_generic_data *gdata)
{
-#ifdef CONFIG_ACPI_APEI_PCIEAER
- struct pci_dev *dev;
-#endif
-
if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
@@ -285,20 +281,6 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
printk(
"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
pfx, pcie->bridge.secondary_status, pcie->bridge.control);
-#ifdef CONFIG_ACPI_APEI_PCIEAER
- dev = pci_get_domain_bus_and_slot(pcie->device_id.segment,
- pcie->device_id.bus, pcie->device_id.function);
- if (!dev) {
- pr_err("PCI AER Cannot get PCI device %04x:%02x:%02x.%d\n",
- pcie->device_id.segment, pcie->device_id.bus,
- pcie->device_id.slot, pcie->device_id.function);
- return;
- }
- if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO)
- cper_print_aer(pfx, dev, gdata->error_severity,
- (struct aer_capability_regs *) pcie->aer_info);
- pci_dev_put(dev);
-#endif
}
static const char *apei_estatus_section_flag_strs[] = {
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index d668a8a..fcd7d91 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -454,7 +454,9 @@ static void ghes_do_proc(struct ghes *ghes,
aer_severity = cper_severity_to_aer(sev);
aer_recover_queue(pcie_err->device_id.segment,
pcie_err->device_id.bus,
- devfn, aer_severity);
+ devfn, aer_severity,
+ (struct aer_capability_regs *)
+ pcie_err->aer_info);
}
}
@@ -917,13 +919,14 @@ static int ghes_probe(struct platform_device *ghes_dev)
break;
case ACPI_HEST_NOTIFY_EXTERNAL:
/* External interrupt vector is GSI */
- if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) {
+ rc = acpi_gsi_to_irq(generic->notify.vector, &ghes->irq);
+ if (rc) {
pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n",
generic->header.source_id);
goto err_edac_unreg;
}
- if (request_irq(ghes->irq, ghes_irq_func,
- 0, "GHES IRQ", ghes)) {
+ rc = request_irq(ghes->irq, ghes_irq_func, 0, "GHES IRQ", ghes);
+ if (rc) {
pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
generic->header.source_id);
goto err_edac_unreg;
diff --git a/drivers/acpi/csrt.c b/drivers/acpi/csrt.c
deleted file mode 100644
index 5c15a91..0000000
--- a/drivers/acpi/csrt.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Support for Core System Resources Table (CSRT)
- *
- * Copyright (C) 2013, Intel Corporation
- * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
- * Andy Shevchenko <andriy.shevchenko@linux.intel.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.
- */
-
-#define pr_fmt(fmt) "ACPI: CSRT: " fmt
-
-#include <linux/acpi.h>
-#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/sizes.h>
-
-ACPI_MODULE_NAME("CSRT");
-
-static int __init acpi_csrt_parse_shared_info(struct platform_device *pdev,
- const struct acpi_csrt_group *grp)
-{
- const struct acpi_csrt_shared_info *si;
- struct resource res[3];
- size_t nres;
- int ret;
-
- memset(res, 0, sizeof(res));
- nres = 0;
-
- si = (const struct acpi_csrt_shared_info *)&grp[1];
- /*
- * The peripherals that are listed on CSRT typically support only
- * 32-bit addresses so we only use the low part of MMIO base for
- * now.
- */
- if (!si->mmio_base_high && si->mmio_base_low) {
- /*
- * There is no size of the memory resource in shared_info
- * so we assume that it is 4k here.
- */
- res[nres].start = si->mmio_base_low;
- res[nres].end = res[0].start + SZ_4K - 1;
- res[nres++].flags = IORESOURCE_MEM;
- }
-
- if (si->gsi_interrupt) {
- int irq = acpi_register_gsi(NULL, si->gsi_interrupt,
- si->interrupt_mode,
- si->interrupt_polarity);
- res[nres].start = irq;
- res[nres].end = irq;
- res[nres++].flags = IORESOURCE_IRQ;
- }
-
- if (si->base_request_line || si->num_handshake_signals) {
- /*
- * We pass the driver a DMA resource describing the range
- * of request lines the device supports.
- */
- res[nres].start = si->base_request_line;
- res[nres].end = res[nres].start + si->num_handshake_signals - 1;
- res[nres++].flags = IORESOURCE_DMA;
- }
-
- ret = platform_device_add_resources(pdev, res, nres);
- if (ret) {
- if (si->gsi_interrupt)
- acpi_unregister_gsi(si->gsi_interrupt);
- return ret;
- }
-
- return 0;
-}
-
-static int __init
-acpi_csrt_parse_resource_group(const struct acpi_csrt_group *grp)
-{
- struct platform_device *pdev;
- char vendor[5], name[16];
- int ret, i;
-
- vendor[0] = grp->vendor_id;
- vendor[1] = grp->vendor_id >> 8;
- vendor[2] = grp->vendor_id >> 16;
- vendor[3] = grp->vendor_id >> 24;
- vendor[4] = '\0';
-
- if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
- return -ENODEV;
-
- snprintf(name, sizeof(name), "%s%04X", vendor, grp->device_id);
- pdev = platform_device_alloc(name, PLATFORM_DEVID_AUTO);
- if (!pdev)
- return -ENOMEM;
-
- /* Add resources based on the shared info */
- ret = acpi_csrt_parse_shared_info(pdev, grp);
- if (ret)
- goto fail;
-
- ret = platform_device_add(pdev);
- if (ret)
- goto fail;
-
- for (i = 0; i < pdev->num_resources; i++)
- dev_dbg(&pdev->dev, "%pR\n", &pdev->resource[i]);
-
- return 0;
-
-fail:
- platform_device_put(pdev);
- return ret;
-}
-
-/*
- * CSRT or Core System Resources Table is a proprietary ACPI table
- * introduced by Microsoft. This table can contain devices that are not in
- * the system DSDT table. In particular DMA controllers might be described
- * here.
- *
- * We present these devices as normal platform devices that don't have ACPI
- * IDs or handle. The platform device name will be something like
- * <VENDOR><DEVID>.<n>.auto for example: INTL9C06.0.auto.
- */
-void __init acpi_csrt_init(void)
-{
- struct acpi_csrt_group *grp, *end;
- struct acpi_table_csrt *csrt;
- acpi_status status;
- int ret;
-
- status = acpi_get_table(ACPI_SIG_CSRT, 0,
- (struct acpi_table_header **)&csrt);
- if (ACPI_FAILURE(status)) {
- if (status != AE_NOT_FOUND)
- pr_warn("failed to get the CSRT table\n");
- return;
- }
-
- pr_debug("parsing CSRT table for devices\n");
-
- grp = (struct acpi_csrt_group *)(csrt + 1);
- end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length);
-
- while (grp < end) {
- ret = acpi_csrt_parse_resource_group(grp);
- if (ret) {
- pr_warn("error in parsing resource group: %d\n", ret);
- return;
- }
-
- grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
- }
-}
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 96de787..318fa32 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -37,68 +37,6 @@
#define _COMPONENT ACPI_POWER_COMPONENT
ACPI_MODULE_NAME("device_pm");
-static DEFINE_MUTEX(acpi_pm_notifier_lock);
-
-/**
- * acpi_add_pm_notifier - Register PM notifier for given ACPI device.
- * @adev: ACPI device to add the notifier for.
- * @context: Context information to pass to the notifier routine.
- *
- * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
- * PM wakeup events. For example, wakeup events may be generated for bridges
- * if one of the devices below the bridge is signaling wakeup, even if the
- * bridge itself doesn't have a wakeup GPE associated with it.
- */
-acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
- acpi_notify_handler handler, void *context)
-{
- acpi_status status = AE_ALREADY_EXISTS;
-
- mutex_lock(&acpi_pm_notifier_lock);
-
- if (adev->wakeup.flags.notifier_present)
- goto out;
-
- status = acpi_install_notify_handler(adev->handle,
- ACPI_SYSTEM_NOTIFY,
- handler, context);
- if (ACPI_FAILURE(status))
- goto out;
-
- adev->wakeup.flags.notifier_present = true;
-
- out:
- mutex_unlock(&acpi_pm_notifier_lock);
- return status;
-}
-
-/**
- * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device.
- * @adev: ACPI device to remove the notifier from.
- */
-acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
- acpi_notify_handler handler)
-{
- acpi_status status = AE_BAD_PARAMETER;
-
- mutex_lock(&acpi_pm_notifier_lock);
-
- if (!adev->wakeup.flags.notifier_present)
- goto out;
-
- status = acpi_remove_notify_handler(adev->handle,
- ACPI_SYSTEM_NOTIFY,
- handler);
- if (ACPI_FAILURE(status))
- goto out;
-
- adev->wakeup.flags.notifier_present = false;
-
- out:
- mutex_unlock(&acpi_pm_notifier_lock);
- return status;
-}
-
/**
* acpi_power_state_string - String representation of ACPI device power state.
* @state: ACPI device power state to return the string representation of.
@@ -340,11 +278,13 @@ int acpi_bus_init_power(struct acpi_device *device)
if (result)
return result;
} else if (state == ACPI_STATE_UNKNOWN) {
- /* No power resources and missing _PSC? Try to force D0. */
+ /*
+ * No power resources and missing _PSC? Cross fingers and make
+ * it D0 in hope that this is what the BIOS put the device into.
+ * [We tried to force D0 here by executing _PS0, but that broke
+ * Toshiba P870-303 in a nasty way.]
+ */
state = ACPI_STATE_D0;
- result = acpi_dev_pm_explicit_set(device, state);
- if (result)
- return result;
}
device->power.state = state;
return 0;
@@ -385,6 +325,69 @@ bool acpi_bus_power_manageable(acpi_handle handle)
}
EXPORT_SYMBOL(acpi_bus_power_manageable);
+#ifdef CONFIG_PM
+static DEFINE_MUTEX(acpi_pm_notifier_lock);
+
+/**
+ * acpi_add_pm_notifier - Register PM notifier for given ACPI device.
+ * @adev: ACPI device to add the notifier for.
+ * @context: Context information to pass to the notifier routine.
+ *
+ * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of
+ * PM wakeup events. For example, wakeup events may be generated for bridges
+ * if one of the devices below the bridge is signaling wakeup, even if the
+ * bridge itself doesn't have a wakeup GPE associated with it.
+ */
+acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
+ acpi_notify_handler handler, void *context)
+{
+ acpi_status status = AE_ALREADY_EXISTS;
+
+ mutex_lock(&acpi_pm_notifier_lock);
+
+ if (adev->wakeup.flags.notifier_present)
+ goto out;
+
+ status = acpi_install_notify_handler(adev->handle,
+ ACPI_SYSTEM_NOTIFY,
+ handler, context);
+ if (ACPI_FAILURE(status))
+ goto out;
+
+ adev->wakeup.flags.notifier_present = true;
+
+ out:
+ mutex_unlock(&acpi_pm_notifier_lock);
+ return status;
+}
+
+/**
+ * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device.
+ * @adev: ACPI device to remove the notifier from.
+ */
+acpi_status acpi_remove_pm_notifier(struct acpi_device *adev,
+ acpi_notify_handler handler)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+
+ mutex_lock(&acpi_pm_notifier_lock);
+
+ if (!adev->wakeup.flags.notifier_present)
+ goto out;
+
+ status = acpi_remove_notify_handler(adev->handle,
+ ACPI_SYSTEM_NOTIFY,
+ handler);
+ if (ACPI_FAILURE(status))
+ goto out;
+
+ adev->wakeup.flags.notifier_present = false;
+
+ out:
+ mutex_unlock(&acpi_pm_notifier_lock);
+ return status;
+}
+
bool acpi_bus_can_wakeup(acpi_handle handle)
{
struct acpi_device *device;
@@ -1023,3 +1026,4 @@ void acpi_dev_pm_remove_dependent(acpi_handle handle, struct device *depdev)
mutex_unlock(&adev->physical_node_lock);
}
EXPORT_SYMBOL_GPL(acpi_dev_pm_remove_dependent);
+#endif /* CONFIG_PM */
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index d45b287..edc0081 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -223,7 +223,7 @@ static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
static int ec_poll(struct acpi_ec *ec)
{
unsigned long flags;
- int repeat = 2; /* number of command restarts */
+ int repeat = 5; /* number of command restarts */
while (repeat--) {
unsigned long delay = jiffies +
msecs_to_jiffies(ec_delay);
@@ -241,8 +241,6 @@ static int ec_poll(struct acpi_ec *ec)
}
advance_transaction(ec, acpi_ec_read_status(ec));
} while (time_before(jiffies, delay));
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
- break;
pr_debug(PREFIX "controller reset, restart transaction\n");
spin_lock_irqsave(&ec->lock, flags);
start_transaction(ec);
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 6f1afd9..297cbf4 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -35,7 +35,6 @@ void acpi_pci_link_init(void);
void acpi_pci_root_hp_init(void);
void acpi_platform_init(void);
int acpi_sysfs_init(void);
-void acpi_csrt_init(void);
#ifdef CONFIG_ACPI_CONTAINER
void acpi_container_init(void);
#else
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 1dd6f6c..e427dc5 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -641,7 +641,9 @@ static void _handle_hotplug_event_root(struct work_struct *work)
/* bus enumerate */
printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
(char *)buffer.pointer);
- if (!root)
+ if (root)
+ acpiphp_check_host_bridge(handle);
+ else
handle_root_bridge_insertion(handle);
break;
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index bec717f..c266cdc 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -95,9 +95,6 @@ static const struct acpi_device_id processor_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, processor_device_ids);
-static SIMPLE_DEV_PM_OPS(acpi_processor_pm,
- acpi_processor_suspend, acpi_processor_resume);
-
static struct acpi_driver acpi_processor_driver = {
.name = "processor",
.class = ACPI_PROCESSOR_CLASS,
@@ -107,7 +104,6 @@ static struct acpi_driver acpi_processor_driver = {
.remove = acpi_processor_remove,
.notify = acpi_processor_notify,
},
- .drv.pm = &acpi_processor_pm,
};
#define INSTALL_NOTIFY_HANDLER 1
@@ -934,6 +930,8 @@ static int __init acpi_processor_init(void)
if (result < 0)
return result;
+ acpi_processor_syscore_init();
+
acpi_processor_install_hotplug_notify();
acpi_thermal_cpufreq_init();
@@ -956,6 +954,8 @@ static void __exit acpi_processor_exit(void)
acpi_processor_uninstall_hotplug_notify();
+ acpi_processor_syscore_exit();
+
acpi_bus_unregister_driver(&acpi_processor_driver);
return;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index f0df2c9..eb133c7 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -34,6 +34,7 @@
#include <linux/sched.h> /* need_resched() */
#include <linux/clockchips.h>
#include <linux/cpuidle.h>
+#include <linux/syscore_ops.h>
/*
* Include the apic definitions for x86 to have the APIC timer related defines
@@ -210,33 +211,41 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
#endif
+#ifdef CONFIG_PM_SLEEP
static u32 saved_bm_rld;
-static void acpi_idle_bm_rld_save(void)
+int acpi_processor_suspend(void)
{
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
+ return 0;
}
-static void acpi_idle_bm_rld_restore(void)
+
+void acpi_processor_resume(void)
{
u32 resumed_bm_rld;
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &resumed_bm_rld);
+ if (resumed_bm_rld == saved_bm_rld)
+ return;
- if (resumed_bm_rld != saved_bm_rld)
- acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
+ acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
}
-int acpi_processor_suspend(struct device *dev)
+static struct syscore_ops acpi_processor_syscore_ops = {
+ .suspend = acpi_processor_suspend,
+ .resume = acpi_processor_resume,
+};
+
+void acpi_processor_syscore_init(void)
{
- acpi_idle_bm_rld_save();
- return 0;
+ register_syscore_ops(&acpi_processor_syscore_ops);
}
-int acpi_processor_resume(struct device *dev)
+void acpi_processor_syscore_exit(void)
{
- acpi_idle_bm_rld_restore();
- return 0;
+ unregister_syscore_ops(&acpi_processor_syscore_ops);
}
+#endif /* CONFIG_PM_SLEEP */
#if defined(CONFIG_X86)
static void tsc_check_state(int state)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index fe158fd..b14ac46 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1017,11 +1017,8 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
return -ENOSYS;
result = driver->ops.add(device);
- if (result) {
- device->driver = NULL;
- device->driver_data = NULL;
+ if (result)
return result;
- }
device->driver = driver;
@@ -1785,7 +1782,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type)
acpi_set_pnp_ids(handle, &pnp, type);
if (!pnp.type.hardware_id)
- return;
+ goto out;
/*
* This relies on the fact that acpi_install_notify_handler() will not
@@ -1800,6 +1797,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type)
}
}
+out:
acpi_free_pnp_ids(&pnp);
}
@@ -2042,7 +2040,6 @@ int __init acpi_scan_init(void)
acpi_pci_link_init();
acpi_platform_init();
acpi_lpss_init();
- acpi_csrt_init();
acpi_container_init();
acpi_memory_hotplug_init();
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index c3932d0..440eadf 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -456,6 +456,30 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dm4 Notebook PC"),
},
},
+ {
+ .callback = video_ignore_initial_backlight,
+ .ident = "HP Pavilion g6 Notebook PC",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion g6 Notebook PC"),
+ },
+ },
+ {
+ .callback = video_ignore_initial_backlight,
+ .ident = "HP 1000 Notebook PC",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP 1000 Notebook PC"),
+ },
+ },
+ {
+ .callback = video_ignore_initial_backlight,
+ .ident = "HP Pavilion m4",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion m4 Notebook PC"),
+ },
+ },
{}
};
@@ -1698,6 +1722,9 @@ static int acpi_video_bus_add(struct acpi_device *device)
int error;
acpi_status status;
+ if (device->handler)
+ return -EINVAL;
+
status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
device->parent->handle, 1,
acpi_video_bus_match, NULL,
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 66f6762..e6bd910 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -161,6 +161,14 @@ static struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"),
},
},
+ {
+ .callback = video_detect_force_vendor,
+ .ident = "Asus UL30A",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
+ },
+ },
{ },
};
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
index 4e94ba2..9d0cf01 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -2,7 +2,7 @@
/*
* acard-ahci.c - ACard AHCI SATA support
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 251e57d3..2b50dfd 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1,7 +1,7 @@
/*
* ahci.c - AHCI SATA support
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -423,6 +423,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
.driver_data = board_ahci_yes_fbs }, /* 88se9125 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a),
.driver_data = board_ahci_yes_fbs }, /* 88se9172 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172),
+ .driver_data = board_ahci_yes_fbs }, /* 88se9172 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9192),
.driver_data = board_ahci_yes_fbs }, /* 88se9172 on some Gigabyte */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x91a3),
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index b830e6c..10b14d4 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -1,7 +1,7 @@
/*
* ahci.h - Common AHCI SATA definitions and declarations
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 2f48123..9a8a674 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1,7 +1,7 @@
/*
* ata_piix.c - Intel PATA/SATA controllers
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -151,6 +151,7 @@ enum piix_controller_ids {
piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */
ich8_sata_snb,
ich8_2port_sata_snb,
+ ich8_2port_sata_byt,
};
struct piix_map_db {
@@ -334,6 +335,9 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x8d60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb },
/* SATA Controller IDE (Wellsburg) */
{ 0x8086, 0x8d68, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (BayTrail) */
+ { 0x8086, 0x0F20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
+ { 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
{ } /* terminate list */
};
@@ -441,6 +445,7 @@ static const struct piix_map_db *piix_map_db_table[] = {
[tolapai_sata] = &tolapai_map_db,
[ich8_sata_snb] = &ich8_map_db,
[ich8_2port_sata_snb] = &ich8_2port_map_db,
+ [ich8_2port_sata_byt] = &ich8_2port_map_db,
};
static struct pci_bits piix_enable_bits[] = {
@@ -1254,6 +1259,16 @@ static struct ata_port_info piix_port_info[] = {
.udma_mask = ATA_UDMA6,
.port_ops = &piix_sata_ops,
},
+
+ [ich8_2port_sata_byt] =
+ {
+ .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR | PIIX_FLAG_PIO16,
+ .pio_mask = ATA_PIO4,
+ .mwdma_mask = ATA_MWDMA2,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &piix_sata_ops,
+ },
+
};
#define AHCI_PCI_BAR 5
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 34c8216..a70ff15 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1,7 +1,7 @@
/*
* libahci.c - Common AHCI SATA low-level routines
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 63c743b..f218427 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1,7 +1,7 @@
/*
* libata-core.c - helper library for ATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
@@ -1602,6 +1602,12 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
qc->tf = *tf;
if (cdb)
memcpy(qc->cdb, cdb, ATAPI_CDB_LEN);
+
+ /* some SATA bridges need us to indicate data xfer direction */
+ if (tf->protocol == ATAPI_PROT_DMA && (dev->flags & ATA_DFLAG_DMADIR) &&
+ dma_dir == DMA_FROM_DEVICE)
+ qc->tf.feature |= ATAPI_DMADIR;
+
qc->flags |= ATA_QCFLAG_RESULT_TF;
qc->dma_dir = dma_dir;
if (dma_dir != DMA_NONE) {
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index f9476fb..c69fcce 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1,7 +1,7 @@
/*
* libata-eh.c - libata error handling
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index dd310b27..0101af5 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1,7 +1,7 @@
/*
* libata-scsi.c - helper library for ATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index d8af325..b603720 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1,7 +1,7 @@
/*
* libata-sff.c - helper library for PCI IDE BMDMA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
index c1bfaf4..980b88e 100644
--- a/drivers/ata/pata_ep93xx.c
+++ b/drivers/ata/pata_ep93xx.c
@@ -933,11 +933,6 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
}
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- err = -ENXIO;
- goto err_rel_gpio;
- }
-
ide_base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(ide_base)) {
err = PTR_ERR(ide_base);
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 5053333..8ea6e6a 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -1,7 +1,7 @@
/*
* pdc_adma.c - Pacific Digital Corporation ADMA
*
- * Maintained by: Mark Lord <mlord@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
*
* Copyright 2005 Mark Lord
*
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index fb0dd87..958ba2a 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -1,7 +1,7 @@
/*
* sata_promise.c - Promise SATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Mikael Pettersson <mikpe@it.uu.se>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index 4799868..249c8a2 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -549,6 +549,7 @@ static void sata_rcar_bmdma_start(struct ata_queued_cmd *qc)
/* start host DMA transaction */
dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ dmactl &= ~ATAPI_CONTROL1_STOP;
dmactl |= ATAPI_CONTROL1_START;
iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
}
@@ -618,17 +619,16 @@ static struct ata_port_operations sata_rcar_port_ops = {
.bmdma_status = sata_rcar_bmdma_status,
};
-static int sata_rcar_serr_interrupt(struct ata_port *ap)
+static void sata_rcar_serr_interrupt(struct ata_port *ap)
{
struct sata_rcar_priv *priv = ap->host->private_data;
struct ata_eh_info *ehi = &ap->link.eh_info;
int freeze = 0;
- int handled = 0;
u32 serror;
serror = ioread32(priv->base + SCRSERR_REG);
if (!serror)
- return 0;
+ return;
DPRINTK("SError @host_intr: 0x%x\n", serror);
@@ -641,7 +641,6 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap)
ata_ehi_push_desc(ehi, "%s", "hotplug");
freeze = serror & SERR_COMM_WAKE ? 0 : 1;
- handled = 1;
}
/* freeze or abort */
@@ -649,11 +648,9 @@ static int sata_rcar_serr_interrupt(struct ata_port *ap)
ata_port_freeze(ap);
else
ata_port_abort(ap);
-
- return handled;
}
-static int sata_rcar_ata_interrupt(struct ata_port *ap)
+static void sata_rcar_ata_interrupt(struct ata_port *ap)
{
struct ata_queued_cmd *qc;
int handled = 0;
@@ -662,7 +659,9 @@ static int sata_rcar_ata_interrupt(struct ata_port *ap)
if (qc)
handled |= ata_bmdma_port_intr(ap, qc);
- return handled;
+ /* be sure to clear ATA interrupt */
+ if (!handled)
+ sata_rcar_check_status(ap);
}
static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
@@ -677,20 +676,21 @@ static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
spin_lock_irqsave(&host->lock, flags);
sataintstat = ioread32(priv->base + SATAINTSTAT_REG);
+ sataintstat &= SATA_RCAR_INT_MASK;
if (!sataintstat)
goto done;
/* ack */
- iowrite32(sataintstat & ~SATA_RCAR_INT_MASK,
- priv->base + SATAINTSTAT_REG);
+ iowrite32(~sataintstat & 0x7ff, priv->base + SATAINTSTAT_REG);
ap = host->ports[0];
if (sataintstat & SATAINTSTAT_ATA)
- handled |= sata_rcar_ata_interrupt(ap);
+ sata_rcar_ata_interrupt(ap);
if (sataintstat & SATAINTSTAT_SERR)
- handled |= sata_rcar_serr_interrupt(ap);
+ sata_rcar_serr_interrupt(ap);
+ handled = 1;
done:
spin_unlock_irqrestore(&host->lock, flags);
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index a7b3167..0ae3ca4 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -1,7 +1,7 @@
/*
* sata_sil.c - Silicon Image SATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 7b7127a..9947010 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -1,7 +1,7 @@
/*
* sata_sx4.c - Promise SATA
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 5913ea9..87f056e 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -1,7 +1,7 @@
/*
* sata_via.c - VIA Serial ATA controllers
*
- * Maintained by: Jeff Garzik <jgarzik@pobox.com>
+ * Maintained by: Tejun Heo <tj@kernel.org>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 77a7480d..62a7607 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -1403,7 +1403,7 @@ static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
rx.host_address = cpu_to_be32 (virt_to_bus (skb->data));
skb->data = skb->head;
- skb->tail = skb->head;
+ skb_reset_tail_pointer(skb);
skb->len = 0;
if (!rx_give (dev, &rx, pool)) {
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 1a68f947..d414331 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -1295,6 +1295,7 @@ int subsys_virtual_register(struct bus_type *subsys,
return subsys_register(subsys, groups, virtual_dir);
}
+EXPORT_SYMBOL_GPL(subsys_virtual_register);
int __init buses_init(void)
{
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 016312437..2499cef 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -572,9 +572,11 @@ int device_create_file(struct device *dev,
if (dev) {
WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
- "Write permission without 'store'\n");
+ "Attribute %s: write permission without 'store'\n",
+ attr->attr.name);
WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
- "Read permission without 'show'\n");
+ "Attribute %s: read permission without 'show'\n",
+ attr->attr.name);
error = sysfs_create_file(&dev->kobj, &attr->attr);
}
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index 39c3252..5da9140 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -61,24 +61,24 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
int dev_pm_put_subsys_data(struct device *dev)
{
struct pm_subsys_data *psd;
- int ret = 0;
+ int ret = 1;
spin_lock_irq(&dev->power.lock);
psd = dev_to_psd(dev);
- if (!psd) {
- ret = -EINVAL;
+ if (!psd)
goto out;
- }
if (--psd->refcount == 0) {
dev->power.subsys_data = NULL;
- kfree(psd);
- ret = 1;
+ } else {
+ psd = NULL;
+ ret = 0;
}
out:
spin_unlock_irq(&dev->power.lock);
+ kfree(psd);
return ret;
}
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index aa0875f..02f490b 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -143,7 +143,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
int registers = 0;
int this_registers, average;
- map->lock(map);
+ map->lock(map->lock_arg);
mem_size = sizeof(*rbtree_ctx);
mem_size += BITS_TO_LONGS(map->cache_present_nbits) * sizeof(long);
@@ -170,7 +170,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
seq_printf(s, "%d nodes, %d registers, average %d registers, used %zu bytes\n",
nodes, registers, average, mem_size);
- map->unlock(map);
+ map->unlock(map->lock_arg);
return 0;
}
@@ -391,8 +391,6 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
rbnode = rb_entry(node, struct regcache_rbtree_node, node);
- if (rbnode->base_reg < min)
- continue;
if (rbnode->base_reg > max)
break;
if (rbnode->base_reg + rbnode->blklen < min)
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 75923f2..507ee2d 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -270,7 +270,7 @@ int regcache_sync(struct regmap *map)
BUG_ON(!map->cache_ops || !map->cache_ops->sync);
- map->lock(map);
+ map->lock(map->lock_arg);
/* Remember the initial bypass state */
bypass = map->cache_bypass;
dev_dbg(map->dev, "Syncing %s cache\n",
@@ -306,7 +306,7 @@ out:
trace_regcache_sync(map->dev, name, "stop");
/* Restore the bypass state */
map->cache_bypass = bypass;
- map->unlock(map);
+ map->unlock(map->lock_arg);
return ret;
}
@@ -333,7 +333,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
BUG_ON(!map->cache_ops || !map->cache_ops->sync);
- map->lock(map);
+ map->lock(map->lock_arg);
/* Remember the initial bypass state */
bypass = map->cache_bypass;
@@ -352,7 +352,7 @@ out:
trace_regcache_sync(map->dev, name, "stop region");
/* Restore the bypass state */
map->cache_bypass = bypass;
- map->unlock(map);
+ map->unlock(map->lock_arg);
return ret;
}
@@ -372,11 +372,11 @@ EXPORT_SYMBOL_GPL(regcache_sync_region);
*/
void regcache_cache_only(struct regmap *map, bool enable)
{
- map->lock(map);
+ map->lock(map->lock_arg);
WARN_ON(map->cache_bypass && enable);
map->cache_only = enable;
trace_regmap_cache_only(map->dev, enable);
- map->unlock(map);
+ map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_cache_only);
@@ -391,9 +391,9 @@ EXPORT_SYMBOL_GPL(regcache_cache_only);
*/
void regcache_mark_dirty(struct regmap *map)
{
- map->lock(map);
+ map->lock(map->lock_arg);
map->cache_dirty = true;
- map->unlock(map);
+ map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_mark_dirty);
@@ -410,11 +410,11 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty);
*/
void regcache_cache_bypass(struct regmap *map, bool enable)
{
- map->lock(map);
+ map->lock(map->lock_arg);
WARN_ON(map->cache_only && enable);
map->cache_bypass = enable;
trace_regmap_cache_bypass(map->dev, enable);
- map->unlock(map);
+ map->unlock(map->lock_arg);
}
EXPORT_SYMBOL_GPL(regcache_cache_bypass);
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 23b701f5..975719b 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -265,6 +265,7 @@ static ssize_t regmap_map_write_file(struct file *file,
char *start = buf;
unsigned long reg, value;
struct regmap *map = file->private_data;
+ int ret;
buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size))
@@ -282,7 +283,9 @@ static ssize_t regmap_map_write_file(struct file *file,
/* Userspace has been fiddling around behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
- regmap_write(map, reg, value);
+ ret = regmap_write(map, reg, value);
+ if (ret < 0)
+ return ret;
return buf_size;
}
#else
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index f1a29f8..9bf4371 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -117,13 +117,13 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
spin_lock(&brd->brd_lock);
idx = sector >> PAGE_SECTORS_SHIFT;
+ page->index = idx;
if (radix_tree_insert(&brd->brd_pages, idx, page)) {
__free_page(page);
page = radix_tree_lookup(&brd->brd_pages, idx);
BUG_ON(!page);
BUG_ON(page->index != idx);
- } else
- page->index = idx;
+ }
spin_unlock(&brd->brd_lock);
radix_tree_preload_end();
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 6374dc1..62b6c2c 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -168,8 +168,6 @@ static irqreturn_t do_cciss_msix_intr(int irq, void *dev_id);
static int cciss_open(struct block_device *bdev, fmode_t mode);
static int cciss_unlocked_open(struct block_device *bdev, fmode_t mode);
static void cciss_release(struct gendisk *disk, fmode_t mode);
-static int do_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg);
static int cciss_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg);
static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
@@ -235,7 +233,7 @@ static const struct block_device_operations cciss_fops = {
.owner = THIS_MODULE,
.open = cciss_unlocked_open,
.release = cciss_release,
- .ioctl = do_ioctl,
+ .ioctl = cciss_ioctl,
.getgeo = cciss_getgeo,
#ifdef CONFIG_COMPAT
.compat_ioctl = cciss_compat_ioctl,
@@ -1143,16 +1141,6 @@ static void cciss_release(struct gendisk *disk, fmode_t mode)
mutex_unlock(&cciss_mutex);
}
-static int do_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned cmd, unsigned long arg)
-{
- int ret;
- mutex_lock(&cciss_mutex);
- ret = cciss_ioctl(bdev, mode, cmd, arg);
- mutex_unlock(&cciss_mutex);
- return ret;
-}
-
#ifdef CONFIG_COMPAT
static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
@@ -1179,7 +1167,7 @@ static int cciss_compat_ioctl(struct block_device *bdev, fmode_t mode,
case CCISS_REGNEWD:
case CCISS_RESCANDISK:
case CCISS_GETLUNINFO:
- return do_ioctl(bdev, mode, cmd, arg);
+ return cciss_ioctl(bdev, mode, cmd, arg);
case CCISS_PASSTHRU32:
return cciss_ioctl32_passthru(bdev, mode, cmd, arg);
@@ -1219,7 +1207,7 @@ static int cciss_ioctl32_passthru(struct block_device *bdev, fmode_t mode,
if (err)
return -EFAULT;
- err = do_ioctl(bdev, mode, CCISS_PASSTHRU, (unsigned long)p);
+ err = cciss_ioctl(bdev, mode, CCISS_PASSTHRU, (unsigned long)p);
if (err)
return err;
err |=
@@ -1261,7 +1249,7 @@ static int cciss_ioctl32_big_passthru(struct block_device *bdev, fmode_t mode,
if (err)
return -EFAULT;
- err = do_ioctl(bdev, mode, CCISS_BIG_PASSTHRU, (unsigned long)p);
+ err = cciss_ioctl(bdev, mode, CCISS_BIG_PASSTHRU, (unsigned long)p);
if (err)
return err;
err |=
@@ -1311,11 +1299,14 @@ static int cciss_getpciinfo(ctlr_info_t *h, void __user *argp)
static int cciss_getintinfo(ctlr_info_t *h, void __user *argp)
{
cciss_coalint_struct intinfo;
+ unsigned long flags;
if (!argp)
return -EINVAL;
+ spin_lock_irqsave(&h->lock, flags);
intinfo.delay = readl(&h->cfgtable->HostWrite.CoalIntDelay);
intinfo.count = readl(&h->cfgtable->HostWrite.CoalIntCount);
+ spin_unlock_irqrestore(&h->lock, flags);
if (copy_to_user
(argp, &intinfo, sizeof(cciss_coalint_struct)))
return -EFAULT;
@@ -1356,12 +1347,15 @@ static int cciss_setintinfo(ctlr_info_t *h, void __user *argp)
static int cciss_getnodename(ctlr_info_t *h, void __user *argp)
{
NodeName_type NodeName;
+ unsigned long flags;
int i;
if (!argp)
return -EINVAL;
+ spin_lock_irqsave(&h->lock, flags);
for (i = 0; i < 16; i++)
NodeName[i] = readb(&h->cfgtable->ServerName[i]);
+ spin_unlock_irqrestore(&h->lock, flags);
if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
return -EFAULT;
return 0;
@@ -1398,10 +1392,13 @@ static int cciss_setnodename(ctlr_info_t *h, void __user *argp)
static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp)
{
Heartbeat_type heartbeat;
+ unsigned long flags;
if (!argp)
return -EINVAL;
+ spin_lock_irqsave(&h->lock, flags);
heartbeat = readl(&h->cfgtable->HeartBeat);
+ spin_unlock_irqrestore(&h->lock, flags);
if (copy_to_user(argp, &heartbeat, sizeof(Heartbeat_type)))
return -EFAULT;
return 0;
@@ -1410,10 +1407,13 @@ static int cciss_getheartbeat(ctlr_info_t *h, void __user *argp)
static int cciss_getbustypes(ctlr_info_t *h, void __user *argp)
{
BusTypes_type BusTypes;
+ unsigned long flags;
if (!argp)
return -EINVAL;
+ spin_lock_irqsave(&h->lock, flags);
BusTypes = readl(&h->cfgtable->BusTypes);
+ spin_unlock_irqrestore(&h->lock, flags);
if (copy_to_user(argp, &BusTypes, sizeof(BusTypes_type)))
return -EFAULT;
return 0;
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 847107e..20dd52a 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -3002,7 +3002,8 @@ static int mtip_hw_debugfs_init(struct driver_data *dd)
static void mtip_hw_debugfs_exit(struct driver_data *dd)
{
- debugfs_remove_recursive(dd->dfs_node);
+ if (dd->dfs_node)
+ debugfs_remove_recursive(dd->dfs_node);
}
@@ -3863,7 +3864,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
struct driver_data *dd = queue->queuedata;
struct scatterlist *sg;
struct bio_vec *bvec;
- int nents = 0;
+ int i, nents = 0;
int tag = 0, unaligned = 0;
if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) {
@@ -3921,11 +3922,12 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
}
/* Create the scatter list for this bio. */
- bio_for_each_segment(bvec, bio, nents) {
+ bio_for_each_segment(bvec, bio, i) {
sg_set_page(&sg[nents],
bvec->bv_page,
bvec->bv_len,
bvec->bv_offset);
+ nents++;
}
/* Issue the read/write. */
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index 8efdfaa..ce79a59 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -629,7 +629,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
struct nvme_command *cmnd;
struct nvme_iod *iod;
enum dma_data_direction dma_dir;
- int cmdid, length, result = -ENOMEM;
+ int cmdid, length, result;
u16 control;
u32 dsmgmt;
int psegs = bio_phys_segments(ns->queue, bio);
@@ -640,6 +640,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
return result;
}
+ result = -ENOMEM;
iod = nvme_alloc_iod(psegs, bio->bi_size, GFP_ATOMIC);
if (!iod)
goto nomem;
@@ -977,6 +978,8 @@ static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout)
if (timeout && !time_after(now, info[cmdid].timeout))
continue;
+ if (info[cmdid].ctx == CMD_CTX_CANCELLED)
+ continue;
dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d\n", cmdid);
ctx = cancel_cmdid(nvmeq, cmdid, &fn);
fn(nvmeq->dev, ctx, &cqe);
@@ -1206,7 +1209,7 @@ struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
if (addr & 3)
return ERR_PTR(-EINVAL);
- if (!length)
+ if (!length || length > INT_MAX - PAGE_SIZE)
return ERR_PTR(-EINVAL);
offset = offset_in_page(addr);
@@ -1227,7 +1230,8 @@ struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
sg_init_table(sg, count);
for (i = 0; i < count; i++) {
sg_set_page(&sg[i], pages[i],
- min_t(int, length, PAGE_SIZE - offset), offset);
+ min_t(unsigned, length, PAGE_SIZE - offset),
+ offset);
length -= (PAGE_SIZE - offset);
offset = 0;
}
@@ -1435,7 +1439,7 @@ static int nvme_user_admin_cmd(struct nvme_dev *dev,
nvme_free_iod(dev, iod);
}
- if (!status && copy_to_user(&ucmd->result, &cmd.result,
+ if ((status >= 0) && copy_to_user(&ucmd->result, &cmd.result,
sizeof(cmd.result)))
status = -EFAULT;
@@ -1633,7 +1637,8 @@ static int set_queue_count(struct nvme_dev *dev, int count)
static int nvme_setup_io_queues(struct nvme_dev *dev)
{
- int result, cpu, i, nr_io_queues, db_bar_size, q_depth;
+ struct pci_dev *pdev = dev->pci_dev;
+ int result, cpu, i, nr_io_queues, db_bar_size, q_depth, q_count;
nr_io_queues = num_online_cpus();
result = set_queue_count(dev, nr_io_queues);
@@ -1642,14 +1647,14 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
if (result < nr_io_queues)
nr_io_queues = result;
+ q_count = nr_io_queues;
/* Deregister the admin queue's interrupt */
free_irq(dev->entry[0].vector, dev->queues[0]);
db_bar_size = 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3));
if (db_bar_size > 8192) {
iounmap(dev->bar);
- dev->bar = ioremap(pci_resource_start(dev->pci_dev, 0),
- db_bar_size);
+ dev->bar = ioremap(pci_resource_start(pdev, 0), db_bar_size);
dev->dbs = ((void __iomem *)dev->bar) + 4096;
dev->queues[0]->q_db = dev->dbs;
}
@@ -1657,19 +1662,36 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
for (i = 0; i < nr_io_queues; i++)
dev->entry[i].entry = i;
for (;;) {
- result = pci_enable_msix(dev->pci_dev, dev->entry,
- nr_io_queues);
+ result = pci_enable_msix(pdev, dev->entry, nr_io_queues);
if (result == 0) {
break;
} else if (result > 0) {
nr_io_queues = result;
continue;
} else {
- nr_io_queues = 1;
+ nr_io_queues = 0;
break;
}
}
+ if (nr_io_queues == 0) {
+ nr_io_queues = q_count;
+ for (;;) {
+ result = pci_enable_msi_block(pdev, nr_io_queues);
+ if (result == 0) {
+ for (i = 0; i < nr_io_queues; i++)
+ dev->entry[i].vector = i + pdev->irq;
+ break;
+ } else if (result > 0) {
+ nr_io_queues = result;
+ continue;
+ } else {
+ nr_io_queues = 1;
+ break;
+ }
+ }
+ }
+
result = queue_request_irq(dev, dev->queues[0], "nvme admin");
/* XXX: handle failure here */
@@ -1850,7 +1872,10 @@ static void nvme_free_dev(struct kref *kref)
{
struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);
nvme_dev_remove(dev);
- pci_disable_msix(dev->pci_dev);
+ if (dev->pci_dev->msi_enabled)
+ pci_disable_msi(dev->pci_dev);
+ else if (dev->pci_dev->msix_enabled)
+ pci_disable_msix(dev->pci_dev);
iounmap(dev->bar);
nvme_release_instance(dev);
nvme_release_prp_pools(dev);
@@ -1923,8 +1948,14 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&dev->namespaces);
dev->pci_dev = pdev;
pci_set_drvdata(pdev, dev);
- dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
- dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+
+ if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)))
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+ else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)))
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ else
+ goto disable;
+
result = nvme_set_instance(dev);
if (result)
goto disable;
@@ -1977,7 +2008,10 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
unmap:
iounmap(dev->bar);
disable_msix:
- pci_disable_msix(pdev);
+ if (dev->pci_dev->msi_enabled)
+ pci_disable_msi(dev->pci_dev);
+ else if (dev->pci_dev->msix_enabled)
+ pci_disable_msix(dev->pci_dev);
nvme_release_instance(dev);
nvme_release_prp_pools(dev);
disable:
diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c
index fed54b0..102de2f 100644
--- a/drivers/block/nvme-scsi.c
+++ b/drivers/block/nvme-scsi.c
@@ -44,7 +44,6 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <scsi/sg.h>
#include <scsi/scsi.h>
@@ -1654,7 +1653,7 @@ static void nvme_trans_modesel_save_bd(struct nvme_ns *ns, u8 *parm_list,
}
}
-static u16 nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr,
+static int nvme_trans_modesel_get_mp(struct nvme_ns *ns, struct sg_io_hdr *hdr,
u8 *mode_page, u8 page_code)
{
int res = SNTI_TRANSLATION_SUCCESS;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 3c08983..f5d0ea1 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -83,7 +83,8 @@
#define MAX_SPEED 0xffff
-#define ZONE(sector, pd) (((sector) + (pd)->offset) & ~((pd)->settings.size - 1))
+#define ZONE(sector, pd) (((sector) + (pd)->offset) & \
+ ~(sector_t)((pd)->settings.size - 1))
static DEFINE_MUTEX(pktcdvd_mutex);
static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index ca63104..3063452 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -55,6 +55,39 @@
#define SECTOR_SHIFT 9
#define SECTOR_SIZE (1ULL << SECTOR_SHIFT)
+/*
+ * Increment the given counter and return its updated value.
+ * If the counter is already 0 it will not be incremented.
+ * If the counter is already at its maximum value returns
+ * -EINVAL without updating it.
+ */
+static int atomic_inc_return_safe(atomic_t *v)
+{
+ unsigned int counter;
+
+ counter = (unsigned int)__atomic_add_unless(v, 1, 0);
+ if (counter <= (unsigned int)INT_MAX)
+ return (int)counter;
+
+ atomic_dec(v);
+
+ return -EINVAL;
+}
+
+/* Decrement the counter. Return the resulting value, or -EINVAL */
+static int atomic_dec_return_safe(atomic_t *v)
+{
+ int counter;
+
+ counter = atomic_dec_return(v);
+ if (counter >= 0)
+ return counter;
+
+ atomic_inc(v);
+
+ return -EINVAL;
+}
+
#define RBD_DRV_NAME "rbd"
#define RBD_DRV_NAME_LONG "rbd (rados block device)"
@@ -100,21 +133,20 @@
* block device image metadata (in-memory version)
*/
struct rbd_image_header {
- /* These four fields never change for a given rbd image */
+ /* These six fields never change for a given rbd image */
char *object_prefix;
- u64 features;
__u8 obj_order;
__u8 crypt_type;
__u8 comp_type;
+ u64 stripe_unit;
+ u64 stripe_count;
+ u64 features; /* Might be changeable someday? */
/* The remaining fields need to be updated occasionally */
u64 image_size;
struct ceph_snap_context *snapc;
- char *snap_names;
- u64 *snap_sizes;
-
- u64 stripe_unit;
- u64 stripe_count;
+ char *snap_names; /* format 1 only */
+ u64 *snap_sizes; /* format 1 only */
};
/*
@@ -225,6 +257,7 @@ struct rbd_obj_request {
};
};
struct page **copyup_pages;
+ u32 copyup_page_count;
struct ceph_osd_request *osd_req;
@@ -257,6 +290,7 @@ struct rbd_img_request {
struct rbd_obj_request *obj_request; /* obj req initiator */
};
struct page **copyup_pages;
+ u32 copyup_page_count;
spinlock_t completion_lock;/* protects next_completion */
u32 next_completion;
rbd_img_callback_t callback;
@@ -311,6 +345,7 @@ struct rbd_device {
struct rbd_spec *parent_spec;
u64 parent_overlap;
+ atomic_t parent_ref;
struct rbd_device *parent;
/* protects updating the header */
@@ -359,7 +394,8 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf,
size_t count);
static ssize_t rbd_remove(struct bus_type *bus, const char *buf,
size_t count);
-static int rbd_dev_image_probe(struct rbd_device *rbd_dev);
+static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping);
+static void rbd_spec_put(struct rbd_spec *spec);
static struct bus_attribute rbd_bus_attrs[] = {
__ATTR(add, S_IWUSR, NULL, rbd_add),
@@ -426,7 +462,8 @@ static void rbd_img_parent_read(struct rbd_obj_request *obj_request);
static void rbd_dev_remove_parent(struct rbd_device *rbd_dev);
static int rbd_dev_refresh(struct rbd_device *rbd_dev);
-static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev);
+static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev);
+static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev);
static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev,
u64 snap_id);
static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
@@ -482,8 +519,8 @@ static const struct block_device_operations rbd_bd_ops = {
};
/*
- * Initialize an rbd client instance.
- * We own *ceph_opts.
+ * Initialize an rbd client instance. Success or not, this function
+ * consumes ceph_opts.
*/
static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts)
{
@@ -638,7 +675,8 @@ static int parse_rbd_opts_token(char *c, void *private)
/*
* Get a ceph client with specific addr and configuration, if one does
- * not exist create it.
+ * not exist create it. Either way, ceph_opts is consumed by this
+ * function.
*/
static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts)
{
@@ -726,88 +764,123 @@ static bool rbd_dev_ondisk_valid(struct rbd_image_header_ondisk *ondisk)
}
/*
- * Create a new header structure, translate header format from the on-disk
- * header.
+ * Fill an rbd image header with information from the given format 1
+ * on-disk header.
*/
-static int rbd_header_from_disk(struct rbd_image_header *header,
+static int rbd_header_from_disk(struct rbd_device *rbd_dev,
struct rbd_image_header_ondisk *ondisk)
{
+ struct rbd_image_header *header = &rbd_dev->header;
+ bool first_time = header->object_prefix == NULL;
+ struct ceph_snap_context *snapc;
+ char *object_prefix = NULL;
+ char *snap_names = NULL;
+ u64 *snap_sizes = NULL;
u32 snap_count;
- size_t len;
size_t size;
+ int ret = -ENOMEM;
u32 i;
- memset(header, 0, sizeof (*header));
+ /* Allocate this now to avoid having to handle failure below */
- snap_count = le32_to_cpu(ondisk->snap_count);
+ if (first_time) {
+ size_t len;
- len = strnlen(ondisk->object_prefix, sizeof (ondisk->object_prefix));
- header->object_prefix = kmalloc(len + 1, GFP_KERNEL);
- if (!header->object_prefix)
- return -ENOMEM;
- memcpy(header->object_prefix, ondisk->object_prefix, len);
- header->object_prefix[len] = '\0';
+ len = strnlen(ondisk->object_prefix,
+ sizeof (ondisk->object_prefix));
+ object_prefix = kmalloc(len + 1, GFP_KERNEL);
+ if (!object_prefix)
+ return -ENOMEM;
+ memcpy(object_prefix, ondisk->object_prefix, len);
+ object_prefix[len] = '\0';
+ }
+
+ /* Allocate the snapshot context and fill it in */
+ snap_count = le32_to_cpu(ondisk->snap_count);
+ snapc = ceph_create_snap_context(snap_count, GFP_KERNEL);
+ if (!snapc)
+ goto out_err;
+ snapc->seq = le64_to_cpu(ondisk->snap_seq);
if (snap_count) {
+ struct rbd_image_snap_ondisk *snaps;
u64 snap_names_len = le64_to_cpu(ondisk->snap_names_len);
- /* Save a copy of the snapshot names */
+ /* We'll keep a copy of the snapshot names... */
- if (snap_names_len > (u64) SIZE_MAX)
- return -EIO;
- header->snap_names = kmalloc(snap_names_len, GFP_KERNEL);
- if (!header->snap_names)
+ if (snap_names_len > (u64)SIZE_MAX)
+ goto out_2big;
+ snap_names = kmalloc(snap_names_len, GFP_KERNEL);
+ if (!snap_names)
+ goto out_err;
+
+ /* ...as well as the array of their sizes. */
+
+ size = snap_count * sizeof (*header->snap_sizes);
+ snap_sizes = kmalloc(size, GFP_KERNEL);
+ if (!snap_sizes)
goto out_err;
+
/*
- * Note that rbd_dev_v1_header_read() guarantees
- * the ondisk buffer we're working with has
+ * Copy the names, and fill in each snapshot's id
+ * and size.
+ *
+ * Note that rbd_dev_v1_header_info() guarantees the
+ * ondisk buffer we're working with has
* snap_names_len bytes beyond the end of the
* snapshot id array, this memcpy() is safe.
*/
- memcpy(header->snap_names, &ondisk->snaps[snap_count],
- snap_names_len);
+ memcpy(snap_names, &ondisk->snaps[snap_count], snap_names_len);
+ snaps = ondisk->snaps;
+ for (i = 0; i < snap_count; i++) {
+ snapc->snaps[i] = le64_to_cpu(snaps[i].id);
+ snap_sizes[i] = le64_to_cpu(snaps[i].image_size);
+ }
+ }
- /* Record each snapshot's size */
+ /* We won't fail any more, fill in the header */
- size = snap_count * sizeof (*header->snap_sizes);
- header->snap_sizes = kmalloc(size, GFP_KERNEL);
- if (!header->snap_sizes)
- goto out_err;
- for (i = 0; i < snap_count; i++)
- header->snap_sizes[i] =
- le64_to_cpu(ondisk->snaps[i].image_size);
+ down_write(&rbd_dev->header_rwsem);
+ if (first_time) {
+ header->object_prefix = object_prefix;
+ header->obj_order = ondisk->options.order;
+ header->crypt_type = ondisk->options.crypt_type;
+ header->comp_type = ondisk->options.comp_type;
+ /* The rest aren't used for format 1 images */
+ header->stripe_unit = 0;
+ header->stripe_count = 0;
+ header->features = 0;
} else {
- header->snap_names = NULL;
- header->snap_sizes = NULL;
+ ceph_put_snap_context(header->snapc);
+ kfree(header->snap_names);
+ kfree(header->snap_sizes);
}
- header->features = 0; /* No features support in v1 images */
- header->obj_order = ondisk->options.order;
- header->crypt_type = ondisk->options.crypt_type;
- header->comp_type = ondisk->options.comp_type;
-
- /* Allocate and fill in the snapshot context */
+ /* The remaining fields always get updated (when we refresh) */
header->image_size = le64_to_cpu(ondisk->image_size);
+ header->snapc = snapc;
+ header->snap_names = snap_names;
+ header->snap_sizes = snap_sizes;
- header->snapc = ceph_create_snap_context(snap_count, GFP_KERNEL);
- if (!header->snapc)
- goto out_err;
- header->snapc->seq = le64_to_cpu(ondisk->snap_seq);
- for (i = 0; i < snap_count; i++)
- header->snapc->snaps[i] = le64_to_cpu(ondisk->snaps[i].id);
+ /* Make sure mapping size is consistent with header info */
- return 0;
+ if (rbd_dev->spec->snap_id == CEPH_NOSNAP || first_time)
+ if (rbd_dev->mapping.size != header->image_size)
+ rbd_dev->mapping.size = header->image_size;
+ up_write(&rbd_dev->header_rwsem);
+
+ return 0;
+out_2big:
+ ret = -EIO;
out_err:
- kfree(header->snap_sizes);
- header->snap_sizes = NULL;
- kfree(header->snap_names);
- header->snap_names = NULL;
- kfree(header->object_prefix);
- header->object_prefix = NULL;
+ kfree(snap_sizes);
+ kfree(snap_names);
+ ceph_put_snap_context(snapc);
+ kfree(object_prefix);
- return -ENOMEM;
+ return ret;
}
static const char *_rbd_dev_v1_snap_name(struct rbd_device *rbd_dev, u32 which)
@@ -934,20 +1007,11 @@ static int rbd_snap_features(struct rbd_device *rbd_dev, u64 snap_id,
static int rbd_dev_mapping_set(struct rbd_device *rbd_dev)
{
- const char *snap_name = rbd_dev->spec->snap_name;
- u64 snap_id;
+ u64 snap_id = rbd_dev->spec->snap_id;
u64 size = 0;
u64 features = 0;
int ret;
- if (strcmp(snap_name, RBD_SNAP_HEAD_NAME)) {
- snap_id = rbd_snap_id_by_name(rbd_dev, snap_name);
- if (snap_id == CEPH_NOSNAP)
- return -ENOENT;
- } else {
- snap_id = CEPH_NOSNAP;
- }
-
ret = rbd_snap_size(rbd_dev, snap_id, &size);
if (ret)
return ret;
@@ -958,11 +1022,6 @@ static int rbd_dev_mapping_set(struct rbd_device *rbd_dev)
rbd_dev->mapping.size = size;
rbd_dev->mapping.features = features;
- /* If we are mapping a snapshot it must be marked read-only */
-
- if (snap_id != CEPH_NOSNAP)
- rbd_dev->mapping.read_only = true;
-
return 0;
}
@@ -970,14 +1029,6 @@ static void rbd_dev_mapping_clear(struct rbd_device *rbd_dev)
{
rbd_dev->mapping.size = 0;
rbd_dev->mapping.features = 0;
- rbd_dev->mapping.read_only = true;
-}
-
-static void rbd_dev_clear_mapping(struct rbd_device *rbd_dev)
-{
- rbd_dev->mapping.size = 0;
- rbd_dev->mapping.features = 0;
- rbd_dev->mapping.read_only = true;
}
static const char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset)
@@ -1342,20 +1393,18 @@ static void rbd_obj_request_put(struct rbd_obj_request *obj_request)
kref_put(&obj_request->kref, rbd_obj_request_destroy);
}
-static void rbd_img_request_get(struct rbd_img_request *img_request)
-{
- dout("%s: img %p (was %d)\n", __func__, img_request,
- atomic_read(&img_request->kref.refcount));
- kref_get(&img_request->kref);
-}
-
+static bool img_request_child_test(struct rbd_img_request *img_request);
+static void rbd_parent_request_destroy(struct kref *kref);
static void rbd_img_request_destroy(struct kref *kref);
static void rbd_img_request_put(struct rbd_img_request *img_request)
{
rbd_assert(img_request != NULL);
dout("%s: img %p (was %d)\n", __func__, img_request,
atomic_read(&img_request->kref.refcount));
- kref_put(&img_request->kref, rbd_img_request_destroy);
+ if (img_request_child_test(img_request))
+ kref_put(&img_request->kref, rbd_parent_request_destroy);
+ else
+ kref_put(&img_request->kref, rbd_img_request_destroy);
}
static inline void rbd_img_obj_request_add(struct rbd_img_request *img_request,
@@ -1472,6 +1521,12 @@ static void img_request_child_set(struct rbd_img_request *img_request)
smp_mb();
}
+static void img_request_child_clear(struct rbd_img_request *img_request)
+{
+ clear_bit(IMG_REQ_CHILD, &img_request->flags);
+ smp_mb();
+}
+
static bool img_request_child_test(struct rbd_img_request *img_request)
{
smp_mb();
@@ -1484,6 +1539,12 @@ static void img_request_layered_set(struct rbd_img_request *img_request)
smp_mb();
}
+static void img_request_layered_clear(struct rbd_img_request *img_request)
+{
+ clear_bit(IMG_REQ_LAYERED, &img_request->flags);
+ smp_mb();
+}
+
static bool img_request_layered_test(struct rbd_img_request *img_request)
{
smp_mb();
@@ -1827,6 +1888,74 @@ static void rbd_obj_request_destroy(struct kref *kref)
kmem_cache_free(rbd_obj_request_cache, obj_request);
}
+/* It's OK to call this for a device with no parent */
+
+static void rbd_spec_put(struct rbd_spec *spec);
+static void rbd_dev_unparent(struct rbd_device *rbd_dev)
+{
+ rbd_dev_remove_parent(rbd_dev);
+ rbd_spec_put(rbd_dev->parent_spec);
+ rbd_dev->parent_spec = NULL;
+ rbd_dev->parent_overlap = 0;
+}
+
+/*
+ * Parent image reference counting is used to determine when an
+ * image's parent fields can be safely torn down--after there are no
+ * more in-flight requests to the parent image. When the last
+ * reference is dropped, cleaning them up is safe.
+ */
+static void rbd_dev_parent_put(struct rbd_device *rbd_dev)
+{
+ int counter;
+
+ if (!rbd_dev->parent_spec)
+ return;
+
+ counter = atomic_dec_return_safe(&rbd_dev->parent_ref);
+ if (counter > 0)
+ return;
+
+ /* Last reference; clean up parent data structures */
+
+ if (!counter)
+ rbd_dev_unparent(rbd_dev);
+ else
+ rbd_warn(rbd_dev, "parent reference underflow\n");
+}
+
+/*
+ * If an image has a non-zero parent overlap, get a reference to its
+ * parent.
+ *
+ * We must get the reference before checking for the overlap to
+ * coordinate properly with zeroing the parent overlap in
+ * rbd_dev_v2_parent_info() when an image gets flattened. We
+ * drop it again if there is no overlap.
+ *
+ * Returns true if the rbd device has a parent with a non-zero
+ * overlap and a reference for it was successfully taken, or
+ * false otherwise.
+ */
+static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
+{
+ int counter;
+
+ if (!rbd_dev->parent_spec)
+ return false;
+
+ counter = atomic_inc_return_safe(&rbd_dev->parent_ref);
+ if (counter > 0 && rbd_dev->parent_overlap)
+ return true;
+
+ /* Image was flattened, but parent is not yet torn down */
+
+ if (counter < 0)
+ rbd_warn(rbd_dev, "parent reference overflow\n");
+
+ return false;
+}
+
/*
* Caller is responsible for filling in the list of object requests
* that comprises the image request, and the Linux request pointer
@@ -1835,8 +1964,7 @@ static void rbd_obj_request_destroy(struct kref *kref)
static struct rbd_img_request *rbd_img_request_create(
struct rbd_device *rbd_dev,
u64 offset, u64 length,
- bool write_request,
- bool child_request)
+ bool write_request)
{
struct rbd_img_request *img_request;
@@ -1861,9 +1989,7 @@ static struct rbd_img_request *rbd_img_request_create(
} else {
img_request->snap_id = rbd_dev->spec->snap_id;
}
- if (child_request)
- img_request_child_set(img_request);
- if (rbd_dev->parent_spec)
+ if (rbd_dev_parent_get(rbd_dev))
img_request_layered_set(img_request);
spin_lock_init(&img_request->completion_lock);
img_request->next_completion = 0;
@@ -1873,9 +1999,6 @@ static struct rbd_img_request *rbd_img_request_create(
INIT_LIST_HEAD(&img_request->obj_requests);
kref_init(&img_request->kref);
- rbd_img_request_get(img_request); /* Avoid a warning */
- rbd_img_request_put(img_request); /* TEMPORARY */
-
dout("%s: rbd_dev %p %s %llu/%llu -> img %p\n", __func__, rbd_dev,
write_request ? "write" : "read", offset, length,
img_request);
@@ -1897,15 +2020,54 @@ static void rbd_img_request_destroy(struct kref *kref)
rbd_img_obj_request_del(img_request, obj_request);
rbd_assert(img_request->obj_request_count == 0);
+ if (img_request_layered_test(img_request)) {
+ img_request_layered_clear(img_request);
+ rbd_dev_parent_put(img_request->rbd_dev);
+ }
+
if (img_request_write_test(img_request))
ceph_put_snap_context(img_request->snapc);
- if (img_request_child_test(img_request))
- rbd_obj_request_put(img_request->obj_request);
-
kmem_cache_free(rbd_img_request_cache, img_request);
}
+static struct rbd_img_request *rbd_parent_request_create(
+ struct rbd_obj_request *obj_request,
+ u64 img_offset, u64 length)
+{
+ struct rbd_img_request *parent_request;
+ struct rbd_device *rbd_dev;
+
+ rbd_assert(obj_request->img_request);
+ rbd_dev = obj_request->img_request->rbd_dev;
+
+ parent_request = rbd_img_request_create(rbd_dev->parent,
+ img_offset, length, false);
+ if (!parent_request)
+ return NULL;
+
+ img_request_child_set(parent_request);
+ rbd_obj_request_get(obj_request);
+ parent_request->obj_request = obj_request;
+
+ return parent_request;
+}
+
+static void rbd_parent_request_destroy(struct kref *kref)
+{
+ struct rbd_img_request *parent_request;
+ struct rbd_obj_request *orig_request;
+
+ parent_request = container_of(kref, struct rbd_img_request, kref);
+ orig_request = parent_request->obj_request;
+
+ parent_request->obj_request = NULL;
+ rbd_obj_request_put(orig_request);
+ img_request_child_clear(parent_request);
+
+ rbd_img_request_destroy(kref);
+}
+
static bool rbd_img_obj_end_request(struct rbd_obj_request *obj_request)
{
struct rbd_img_request *img_request;
@@ -2114,7 +2276,7 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
{
struct rbd_img_request *img_request;
struct rbd_device *rbd_dev;
- u64 length;
+ struct page **pages;
u32 page_count;
rbd_assert(obj_request->type == OBJ_REQUEST_BIO);
@@ -2124,12 +2286,14 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
rbd_dev = img_request->rbd_dev;
rbd_assert(rbd_dev);
- length = (u64)1 << rbd_dev->header.obj_order;
- page_count = (u32)calc_pages_for(0, length);
- rbd_assert(obj_request->copyup_pages);
- ceph_release_page_vector(obj_request->copyup_pages, page_count);
+ pages = obj_request->copyup_pages;
+ rbd_assert(pages != NULL);
obj_request->copyup_pages = NULL;
+ page_count = obj_request->copyup_page_count;
+ rbd_assert(page_count);
+ obj_request->copyup_page_count = 0;
+ ceph_release_page_vector(pages, page_count);
/*
* We want the transfer count to reflect the size of the
@@ -2153,9 +2317,11 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
struct ceph_osd_client *osdc;
struct rbd_device *rbd_dev;
struct page **pages;
- int result;
- u64 obj_size;
- u64 xferred;
+ u32 page_count;
+ int img_result;
+ u64 parent_length;
+ u64 offset;
+ u64 length;
rbd_assert(img_request_child_test(img_request));
@@ -2164,46 +2330,74 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
pages = img_request->copyup_pages;
rbd_assert(pages != NULL);
img_request->copyup_pages = NULL;
+ page_count = img_request->copyup_page_count;
+ rbd_assert(page_count);
+ img_request->copyup_page_count = 0;
orig_request = img_request->obj_request;
rbd_assert(orig_request != NULL);
- rbd_assert(orig_request->type == OBJ_REQUEST_BIO);
- result = img_request->result;
- obj_size = img_request->length;
- xferred = img_request->xferred;
+ rbd_assert(obj_request_type_valid(orig_request->type));
+ img_result = img_request->result;
+ parent_length = img_request->length;
+ rbd_assert(parent_length == img_request->xferred);
+ rbd_img_request_put(img_request);
- rbd_dev = img_request->rbd_dev;
+ rbd_assert(orig_request->img_request);
+ rbd_dev = orig_request->img_request->rbd_dev;
rbd_assert(rbd_dev);
- rbd_assert(obj_size == (u64)1 << rbd_dev->header.obj_order);
- rbd_img_request_put(img_request);
+ /*
+ * If the overlap has become 0 (most likely because the
+ * image has been flattened) we need to free the pages
+ * and re-submit the original write request.
+ */
+ if (!rbd_dev->parent_overlap) {
+ struct ceph_osd_client *osdc;
- if (result)
- goto out_err;
+ ceph_release_page_vector(pages, page_count);
+ osdc = &rbd_dev->rbd_client->client->osdc;
+ img_result = rbd_obj_request_submit(osdc, orig_request);
+ if (!img_result)
+ return;
+ }
- /* Allocate the new copyup osd request for the original request */
+ if (img_result)
+ goto out_err;
- result = -ENOMEM;
- rbd_assert(!orig_request->osd_req);
+ /*
+ * The original osd request is of no use to use any more.
+ * We need a new one that can hold the two ops in a copyup
+ * request. Allocate the new copyup osd request for the
+ * original request, and release the old one.
+ */
+ img_result = -ENOMEM;
osd_req = rbd_osd_req_create_copyup(orig_request);
if (!osd_req)
goto out_err;
+ rbd_osd_req_destroy(orig_request->osd_req);
orig_request->osd_req = osd_req;
orig_request->copyup_pages = pages;
+ orig_request->copyup_page_count = page_count;
/* Initialize the copyup op */
osd_req_op_cls_init(osd_req, 0, CEPH_OSD_OP_CALL, "rbd", "copyup");
- osd_req_op_cls_request_data_pages(osd_req, 0, pages, obj_size, 0,
+ osd_req_op_cls_request_data_pages(osd_req, 0, pages, parent_length, 0,
false, false);
/* Then the original write request op */
+ offset = orig_request->offset;
+ length = orig_request->length;
osd_req_op_extent_init(osd_req, 1, CEPH_OSD_OP_WRITE,
- orig_request->offset,
- orig_request->length, 0, 0);
- osd_req_op_extent_osd_data_bio(osd_req, 1, orig_request->bio_list,
- orig_request->length);
+ offset, length, 0, 0);
+ if (orig_request->type == OBJ_REQUEST_BIO)
+ osd_req_op_extent_osd_data_bio(osd_req, 1,
+ orig_request->bio_list, length);
+ else
+ osd_req_op_extent_osd_data_pages(osd_req, 1,
+ orig_request->pages, length,
+ offset & ~PAGE_MASK, false, false);
rbd_osd_req_format_write(orig_request);
@@ -2211,13 +2405,13 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
orig_request->callback = rbd_img_obj_copyup_callback;
osdc = &rbd_dev->rbd_client->client->osdc;
- result = rbd_obj_request_submit(osdc, orig_request);
- if (!result)
+ img_result = rbd_obj_request_submit(osdc, orig_request);
+ if (!img_result)
return;
out_err:
/* Record the error code and complete the request */
- orig_request->result = result;
+ orig_request->result = img_result;
orig_request->xferred = 0;
obj_request_done_set(orig_request);
rbd_obj_request_complete(orig_request);
@@ -2249,7 +2443,7 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request)
int result;
rbd_assert(obj_request_img_data_test(obj_request));
- rbd_assert(obj_request->type == OBJ_REQUEST_BIO);
+ rbd_assert(obj_request_type_valid(obj_request->type));
img_request = obj_request->img_request;
rbd_assert(img_request != NULL);
@@ -2257,15 +2451,6 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request)
rbd_assert(rbd_dev->parent != NULL);
/*
- * First things first. The original osd request is of no
- * use to use any more, we'll need a new one that can hold
- * the two ops in a copyup request. We'll get that later,
- * but for now we can release the old one.
- */
- rbd_osd_req_destroy(obj_request->osd_req);
- obj_request->osd_req = NULL;
-
- /*
* Determine the byte range covered by the object in the
* child image to which the original request was to be sent.
*/
@@ -2295,18 +2480,16 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request)
}
result = -ENOMEM;
- parent_request = rbd_img_request_create(rbd_dev->parent,
- img_offset, length,
- false, true);
+ parent_request = rbd_parent_request_create(obj_request,
+ img_offset, length);
if (!parent_request)
goto out_err;
- rbd_obj_request_get(obj_request);
- parent_request->obj_request = obj_request;
result = rbd_img_request_fill(parent_request, OBJ_REQUEST_PAGES, pages);
if (result)
goto out_err;
parent_request->copyup_pages = pages;
+ parent_request->copyup_page_count = page_count;
parent_request->callback = rbd_img_obj_parent_read_full_callback;
result = rbd_img_request_submit(parent_request);
@@ -2314,6 +2497,7 @@ static int rbd_img_obj_parent_read_full(struct rbd_obj_request *obj_request)
return 0;
parent_request->copyup_pages = NULL;
+ parent_request->copyup_page_count = 0;
parent_request->obj_request = NULL;
rbd_obj_request_put(obj_request);
out_err:
@@ -2331,6 +2515,7 @@ out_err:
static void rbd_img_obj_exists_callback(struct rbd_obj_request *obj_request)
{
struct rbd_obj_request *orig_request;
+ struct rbd_device *rbd_dev;
int result;
rbd_assert(!obj_request_img_data_test(obj_request));
@@ -2353,8 +2538,21 @@ static void rbd_img_obj_exists_callback(struct rbd_obj_request *obj_request)
obj_request->xferred, obj_request->length);
rbd_obj_request_put(obj_request);
- rbd_assert(orig_request);
- rbd_assert(orig_request->img_request);
+ /*
+ * If the overlap has become 0 (most likely because the
+ * image has been flattened) we need to free the pages
+ * and re-submit the original write request.
+ */
+ rbd_dev = orig_request->img_request->rbd_dev;
+ if (!rbd_dev->parent_overlap) {
+ struct ceph_osd_client *osdc;
+
+ rbd_obj_request_put(orig_request);
+ osdc = &rbd_dev->rbd_client->client->osdc;
+ result = rbd_obj_request_submit(osdc, orig_request);
+ if (!result)
+ return;
+ }
/*
* Our only purpose here is to determine whether the object
@@ -2512,14 +2710,36 @@ static void rbd_img_parent_read_callback(struct rbd_img_request *img_request)
struct rbd_obj_request *obj_request;
struct rbd_device *rbd_dev;
u64 obj_end;
+ u64 img_xferred;
+ int img_result;
rbd_assert(img_request_child_test(img_request));
+ /* First get what we need from the image request and release it */
+
obj_request = img_request->obj_request;
+ img_xferred = img_request->xferred;
+ img_result = img_request->result;
+ rbd_img_request_put(img_request);
+
+ /*
+ * If the overlap has become 0 (most likely because the
+ * image has been flattened) we need to re-submit the
+ * original request.
+ */
rbd_assert(obj_request);
rbd_assert(obj_request->img_request);
+ rbd_dev = obj_request->img_request->rbd_dev;
+ if (!rbd_dev->parent_overlap) {
+ struct ceph_osd_client *osdc;
- obj_request->result = img_request->result;
+ osdc = &rbd_dev->rbd_client->client->osdc;
+ img_result = rbd_obj_request_submit(osdc, obj_request);
+ if (!img_result)
+ return;
+ }
+
+ obj_request->result = img_result;
if (obj_request->result)
goto out;
@@ -2532,7 +2752,6 @@ static void rbd_img_parent_read_callback(struct rbd_img_request *img_request)
*/
rbd_assert(obj_request->img_offset < U64_MAX - obj_request->length);
obj_end = obj_request->img_offset + obj_request->length;
- rbd_dev = obj_request->img_request->rbd_dev;
if (obj_end > rbd_dev->parent_overlap) {
u64 xferred = 0;
@@ -2540,43 +2759,39 @@ static void rbd_img_parent_read_callback(struct rbd_img_request *img_request)
xferred = rbd_dev->parent_overlap -
obj_request->img_offset;
- obj_request->xferred = min(img_request->xferred, xferred);
+ obj_request->xferred = min(img_xferred, xferred);
} else {
- obj_request->xferred = img_request->xferred;
+ obj_request->xferred = img_xferred;
}
out:
- rbd_img_request_put(img_request);
rbd_img_obj_request_read_callback(obj_request);
rbd_obj_request_complete(obj_request);
}
static void rbd_img_parent_read(struct rbd_obj_request *obj_request)
{
- struct rbd_device *rbd_dev;
struct rbd_img_request *img_request;
int result;
rbd_assert(obj_request_img_data_test(obj_request));
rbd_assert(obj_request->img_request != NULL);
rbd_assert(obj_request->result == (s32) -ENOENT);
- rbd_assert(obj_request->type == OBJ_REQUEST_BIO);
+ rbd_assert(obj_request_type_valid(obj_request->type));
- rbd_dev = obj_request->img_request->rbd_dev;
- rbd_assert(rbd_dev->parent != NULL);
/* rbd_read_finish(obj_request, obj_request->length); */
- img_request = rbd_img_request_create(rbd_dev->parent,
+ img_request = rbd_parent_request_create(obj_request,
obj_request->img_offset,
- obj_request->length,
- false, true);
+ obj_request->length);
result = -ENOMEM;
if (!img_request)
goto out_err;
- rbd_obj_request_get(obj_request);
- img_request->obj_request = obj_request;
-
- result = rbd_img_request_fill(img_request, OBJ_REQUEST_BIO,
- obj_request->bio_list);
+ if (obj_request->type == OBJ_REQUEST_BIO)
+ result = rbd_img_request_fill(img_request, OBJ_REQUEST_BIO,
+ obj_request->bio_list);
+ else
+ result = rbd_img_request_fill(img_request, OBJ_REQUEST_PAGES,
+ obj_request->pages);
if (result)
goto out_err;
@@ -2626,6 +2841,7 @@ out:
static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
{
struct rbd_device *rbd_dev = (struct rbd_device *)data;
+ int ret;
if (!rbd_dev)
return;
@@ -2633,7 +2849,9 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
dout("%s: \"%s\" notify_id %llu opcode %u\n", __func__,
rbd_dev->header_name, (unsigned long long)notify_id,
(unsigned int)opcode);
- (void)rbd_dev_refresh(rbd_dev);
+ ret = rbd_dev_refresh(rbd_dev);
+ if (ret)
+ rbd_warn(rbd_dev, ": header refresh error (%d)\n", ret);
rbd_obj_notify_ack(rbd_dev, notify_id);
}
@@ -2642,7 +2860,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
* Request sync osd watch/unwatch. The value of "start" determines
* whether a watch request is being initiated or torn down.
*/
-static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, int start)
+static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start)
{
struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
struct rbd_obj_request *obj_request;
@@ -2676,7 +2894,7 @@ static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, int start)
rbd_dev->watch_request->osd_req);
osd_req_op_watch_init(obj_request->osd_req, 0, CEPH_OSD_OP_WATCH,
- rbd_dev->watch_event->cookie, 0, start);
+ rbd_dev->watch_event->cookie, 0, start ? 1 : 0);
rbd_osd_req_format_write(obj_request);
ret = rbd_obj_request_submit(osdc, obj_request);
@@ -2869,9 +3087,16 @@ static void rbd_request_fn(struct request_queue *q)
goto end_request; /* Shouldn't happen */
}
+ result = -EIO;
+ if (offset + length > rbd_dev->mapping.size) {
+ rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)\n",
+ offset, length, rbd_dev->mapping.size);
+ goto end_request;
+ }
+
result = -ENOMEM;
img_request = rbd_img_request_create(rbd_dev, offset, length,
- write_request, false);
+ write_request);
if (!img_request)
goto end_request;
@@ -3022,17 +3247,11 @@ out:
}
/*
- * Read the complete header for the given rbd device.
- *
- * Returns a pointer to a dynamically-allocated buffer containing
- * the complete and validated header. Caller can pass the address
- * of a variable that will be filled in with the version of the
- * header object at the time it was read.
- *
- * Returns a pointer-coded errno if a failure occurs.
+ * Read the complete header for the given rbd device. On successful
+ * return, the rbd_dev->header field will contain up-to-date
+ * information about the image.
*/
-static struct rbd_image_header_ondisk *
-rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
+static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev)
{
struct rbd_image_header_ondisk *ondisk = NULL;
u32 snap_count = 0;
@@ -3057,22 +3276,22 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
size += names_size;
ondisk = kmalloc(size, GFP_KERNEL);
if (!ondisk)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
ret = rbd_obj_read_sync(rbd_dev, rbd_dev->header_name,
0, size, ondisk);
if (ret < 0)
- goto out_err;
+ goto out;
if ((size_t)ret < size) {
ret = -ENXIO;
rbd_warn(rbd_dev, "short header read (want %zd got %d)",
size, ret);
- goto out_err;
+ goto out;
}
if (!rbd_dev_ondisk_valid(ondisk)) {
ret = -ENXIO;
rbd_warn(rbd_dev, "invalid header");
- goto out_err;
+ goto out;
}
names_size = le64_to_cpu(ondisk->snap_names_len);
@@ -3080,85 +3299,13 @@ rbd_dev_v1_header_read(struct rbd_device *rbd_dev)
snap_count = le32_to_cpu(ondisk->snap_count);
} while (snap_count != want_count);
- return ondisk;
-
-out_err:
- kfree(ondisk);
-
- return ERR_PTR(ret);
-}
-
-/*
- * reload the ondisk the header
- */
-static int rbd_read_header(struct rbd_device *rbd_dev,
- struct rbd_image_header *header)
-{
- struct rbd_image_header_ondisk *ondisk;
- int ret;
-
- ondisk = rbd_dev_v1_header_read(rbd_dev);
- if (IS_ERR(ondisk))
- return PTR_ERR(ondisk);
- ret = rbd_header_from_disk(header, ondisk);
+ ret = rbd_header_from_disk(rbd_dev, ondisk);
+out:
kfree(ondisk);
return ret;
}
-static void rbd_update_mapping_size(struct rbd_device *rbd_dev)
-{
- if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
- return;
-
- if (rbd_dev->mapping.size != rbd_dev->header.image_size) {
- sector_t size;
-
- rbd_dev->mapping.size = rbd_dev->header.image_size;
- size = (sector_t)rbd_dev->mapping.size / SECTOR_SIZE;
- dout("setting size to %llu sectors", (unsigned long long)size);
- set_capacity(rbd_dev->disk, size);
- }
-}
-
-/*
- * only read the first part of the ondisk header, without the snaps info
- */
-static int rbd_dev_v1_refresh(struct rbd_device *rbd_dev)
-{
- int ret;
- struct rbd_image_header h;
-
- ret = rbd_read_header(rbd_dev, &h);
- if (ret < 0)
- return ret;
-
- down_write(&rbd_dev->header_rwsem);
-
- /* Update image size, and check for resize of mapped image */
- rbd_dev->header.image_size = h.image_size;
- rbd_update_mapping_size(rbd_dev);
-
- /* rbd_dev->header.object_prefix shouldn't change */
- kfree(rbd_dev->header.snap_sizes);
- kfree(rbd_dev->header.snap_names);
- /* osd requests may still refer to snapc */
- ceph_put_snap_context(rbd_dev->header.snapc);
-
- rbd_dev->header.image_size = h.image_size;
- rbd_dev->header.snapc = h.snapc;
- rbd_dev->header.snap_names = h.snap_names;
- rbd_dev->header.snap_sizes = h.snap_sizes;
- /* Free the extra copy of the object prefix */
- if (strcmp(rbd_dev->header.object_prefix, h.object_prefix))
- rbd_warn(rbd_dev, "object prefix changed (ignoring)");
- kfree(h.object_prefix);
-
- up_write(&rbd_dev->header_rwsem);
-
- return ret;
-}
-
/*
* Clear the rbd device's EXISTS flag if the snapshot it's mapped to
* has disappeared from the (just updated) snapshot context.
@@ -3180,26 +3327,29 @@ static void rbd_exists_validate(struct rbd_device *rbd_dev)
static int rbd_dev_refresh(struct rbd_device *rbd_dev)
{
- u64 image_size;
+ u64 mapping_size;
int ret;
rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
- image_size = rbd_dev->header.image_size;
+ mapping_size = rbd_dev->mapping.size;
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
if (rbd_dev->image_format == 1)
- ret = rbd_dev_v1_refresh(rbd_dev);
+ ret = rbd_dev_v1_header_info(rbd_dev);
else
- ret = rbd_dev_v2_refresh(rbd_dev);
+ ret = rbd_dev_v2_header_info(rbd_dev);
/* If it's a mapped snapshot, validate its EXISTS flag */
rbd_exists_validate(rbd_dev);
mutex_unlock(&ctl_mutex);
- if (ret)
- rbd_warn(rbd_dev, "got notification but failed to "
- " update snaps: %d\n", ret);
- if (image_size != rbd_dev->header.image_size)
+ if (mapping_size != rbd_dev->mapping.size) {
+ sector_t size;
+
+ size = (sector_t)rbd_dev->mapping.size / SECTOR_SIZE;
+ dout("setting size to %llu sectors", (unsigned long long)size);
+ set_capacity(rbd_dev->disk, size);
revalidate_disk(rbd_dev->disk);
+ }
return ret;
}
@@ -3403,6 +3553,8 @@ static ssize_t rbd_image_refresh(struct device *dev,
int ret;
ret = rbd_dev_refresh(rbd_dev);
+ if (ret)
+ rbd_warn(rbd_dev, ": manual header refresh error (%d)\n", ret);
return ret < 0 ? ret : size;
}
@@ -3501,6 +3653,7 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
spin_lock_init(&rbd_dev->lock);
rbd_dev->flags = 0;
+ atomic_set(&rbd_dev->parent_ref, 0);
INIT_LIST_HEAD(&rbd_dev->node);
init_rwsem(&rbd_dev->header_rwsem);
@@ -3650,6 +3803,7 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
__le64 snapid;
void *p;
void *end;
+ u64 pool_id;
char *image_id;
u64 overlap;
int ret;
@@ -3680,18 +3834,37 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
p = reply_buf;
end = reply_buf + ret;
ret = -ERANGE;
- ceph_decode_64_safe(&p, end, parent_spec->pool_id, out_err);
- if (parent_spec->pool_id == CEPH_NOPOOL)
+ ceph_decode_64_safe(&p, end, pool_id, out_err);
+ if (pool_id == CEPH_NOPOOL) {
+ /*
+ * Either the parent never existed, or we have
+ * record of it but the image got flattened so it no
+ * longer has a parent. When the parent of a
+ * layered image disappears we immediately set the
+ * overlap to 0. The effect of this is that all new
+ * requests will be treated as if the image had no
+ * parent.
+ */
+ if (rbd_dev->parent_overlap) {
+ rbd_dev->parent_overlap = 0;
+ smp_mb();
+ rbd_dev_parent_put(rbd_dev);
+ pr_info("%s: clone image has been flattened\n",
+ rbd_dev->disk->disk_name);
+ }
+
goto out; /* No parent? No problem. */
+ }
/* The ceph file layout needs to fit pool id in 32 bits */
ret = -EIO;
- if (parent_spec->pool_id > (u64)U32_MAX) {
+ if (pool_id > (u64)U32_MAX) {
rbd_warn(NULL, "parent pool id too large (%llu > %u)\n",
- (unsigned long long)parent_spec->pool_id, U32_MAX);
+ (unsigned long long)pool_id, U32_MAX);
goto out_err;
}
+ parent_spec->pool_id = pool_id;
image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL);
if (IS_ERR(image_id)) {
@@ -3702,9 +3875,14 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
ceph_decode_64_safe(&p, end, parent_spec->snap_id, out_err);
ceph_decode_64_safe(&p, end, overlap, out_err);
- rbd_dev->parent_overlap = overlap;
- rbd_dev->parent_spec = parent_spec;
- parent_spec = NULL; /* rbd_dev now owns this */
+ if (overlap) {
+ rbd_spec_put(rbd_dev->parent_spec);
+ rbd_dev->parent_spec = parent_spec;
+ parent_spec = NULL; /* rbd_dev now owns this */
+ rbd_dev->parent_overlap = overlap;
+ } else {
+ rbd_warn(rbd_dev, "ignoring parent of clone with overlap 0\n");
+ }
out:
ret = 0;
out_err:
@@ -4002,6 +4180,7 @@ static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev)
for (i = 0; i < snap_count; i++)
snapc->snaps[i] = ceph_decode_64(&p);
+ ceph_put_snap_context(rbd_dev->header.snapc);
rbd_dev->header.snapc = snapc;
dout(" snap context seq = %llu, snap_count = %u\n",
@@ -4053,21 +4232,56 @@ out:
return snap_name;
}
-static int rbd_dev_v2_refresh(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
{
+ bool first_time = rbd_dev->header.object_prefix == NULL;
int ret;
down_write(&rbd_dev->header_rwsem);
+ if (first_time) {
+ ret = rbd_dev_v2_header_onetime(rbd_dev);
+ if (ret)
+ goto out;
+ }
+
+ /*
+ * If the image supports layering, get the parent info. We
+ * need to probe the first time regardless. Thereafter we
+ * only need to if there's a parent, to see if it has
+ * disappeared due to the mapped image getting flattened.
+ */
+ if (rbd_dev->header.features & RBD_FEATURE_LAYERING &&
+ (first_time || rbd_dev->parent_spec)) {
+ bool warn;
+
+ ret = rbd_dev_v2_parent_info(rbd_dev);
+ if (ret)
+ goto out;
+
+ /*
+ * Print a warning if this is the initial probe and
+ * the image has a parent. Don't print it if the
+ * image now being probed is itself a parent. We
+ * can tell at this point because we won't know its
+ * pool name yet (just its pool id).
+ */
+ warn = rbd_dev->parent_spec && rbd_dev->spec->pool_name;
+ if (first_time && warn)
+ rbd_warn(rbd_dev, "WARNING: kernel layering "
+ "is EXPERIMENTAL!");
+ }
+
ret = rbd_dev_v2_image_size(rbd_dev);
if (ret)
goto out;
- rbd_update_mapping_size(rbd_dev);
+
+ if (rbd_dev->spec->snap_id == CEPH_NOSNAP)
+ if (rbd_dev->mapping.size != rbd_dev->header.image_size)
+ rbd_dev->mapping.size = rbd_dev->header.image_size;
ret = rbd_dev_v2_snap_context(rbd_dev);
dout("rbd_dev_v2_snap_context returned %d\n", ret);
- if (ret)
- goto out;
out:
up_write(&rbd_dev->header_rwsem);
@@ -4484,16 +4698,18 @@ out:
return ret;
}
-/* Undo whatever state changes are made by v1 or v2 image probe */
-
+/*
+ * Undo whatever state changes are made by v1 or v2 header info
+ * call.
+ */
static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
{
struct rbd_image_header *header;
- rbd_dev_remove_parent(rbd_dev);
- rbd_spec_put(rbd_dev->parent_spec);
- rbd_dev->parent_spec = NULL;
- rbd_dev->parent_overlap = 0;
+ /* Drop parent reference unless it's already been done (or none) */
+
+ if (rbd_dev->parent_overlap)
+ rbd_dev_parent_put(rbd_dev);
/* Free dynamic fields from the header, then zero it out */
@@ -4505,72 +4721,22 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
memset(header, 0, sizeof (*header));
}
-static int rbd_dev_v1_probe(struct rbd_device *rbd_dev)
+static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev)
{
int ret;
- /* Populate rbd image metadata */
-
- ret = rbd_read_header(rbd_dev, &rbd_dev->header);
- if (ret < 0)
- goto out_err;
-
- /* Version 1 images have no parent (no layering) */
-
- rbd_dev->parent_spec = NULL;
- rbd_dev->parent_overlap = 0;
-
- dout("discovered version 1 image, header name is %s\n",
- rbd_dev->header_name);
-
- return 0;
-
-out_err:
- kfree(rbd_dev->header_name);
- rbd_dev->header_name = NULL;
- kfree(rbd_dev->spec->image_id);
- rbd_dev->spec->image_id = NULL;
-
- return ret;
-}
-
-static int rbd_dev_v2_probe(struct rbd_device *rbd_dev)
-{
- int ret;
-
- ret = rbd_dev_v2_image_size(rbd_dev);
- if (ret)
- goto out_err;
-
- /* Get the object prefix (a.k.a. block_name) for the image */
-
ret = rbd_dev_v2_object_prefix(rbd_dev);
if (ret)
goto out_err;
- /* Get the and check features for the image */
-
+ /*
+ * Get the and check features for the image. Currently the
+ * features are assumed to never change.
+ */
ret = rbd_dev_v2_features(rbd_dev);
if (ret)
goto out_err;
- /* If the image supports layering, get the parent info */
-
- if (rbd_dev->header.features & RBD_FEATURE_LAYERING) {
- ret = rbd_dev_v2_parent_info(rbd_dev);
- if (ret)
- goto out_err;
-
- /*
- * Don't print a warning for parent images. We can
- * tell this point because we won't know its pool
- * name yet (just its pool id).
- */
- if (rbd_dev->spec->pool_name)
- rbd_warn(rbd_dev, "WARNING: kernel layering "
- "is EXPERIMENTAL!");
- }
-
/* If the image supports fancy striping, get its parameters */
if (rbd_dev->header.features & RBD_FEATURE_STRIPINGV2) {
@@ -4578,28 +4744,11 @@ static int rbd_dev_v2_probe(struct rbd_device *rbd_dev)
if (ret < 0)
goto out_err;
}
-
- /* crypto and compression type aren't (yet) supported for v2 images */
-
- rbd_dev->header.crypt_type = 0;
- rbd_dev->header.comp_type = 0;
-
- /* Get the snapshot context, plus the header version */
-
- ret = rbd_dev_v2_snap_context(rbd_dev);
- if (ret)
- goto out_err;
-
- dout("discovered version 2 image, header name is %s\n",
- rbd_dev->header_name);
+ /* No support for crypto and compression type format 2 images */
return 0;
out_err:
- rbd_dev->parent_overlap = 0;
- rbd_spec_put(rbd_dev->parent_spec);
- rbd_dev->parent_spec = NULL;
- kfree(rbd_dev->header_name);
- rbd_dev->header_name = NULL;
+ rbd_dev->header.features = 0;
kfree(rbd_dev->header.object_prefix);
rbd_dev->header.object_prefix = NULL;
@@ -4628,15 +4777,16 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev)
if (!parent)
goto out_err;
- ret = rbd_dev_image_probe(parent);
+ ret = rbd_dev_image_probe(parent, false);
if (ret < 0)
goto out_err;
rbd_dev->parent = parent;
+ atomic_set(&rbd_dev->parent_ref, 1);
return 0;
out_err:
if (parent) {
- rbd_spec_put(rbd_dev->parent_spec);
+ rbd_dev_unparent(rbd_dev);
kfree(rbd_dev->header_name);
rbd_dev_destroy(parent);
} else {
@@ -4651,10 +4801,6 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
{
int ret;
- ret = rbd_dev_mapping_set(rbd_dev);
- if (ret)
- return ret;
-
/* generate unique id: find highest unique id, add one */
rbd_dev_id_get(rbd_dev);
@@ -4676,13 +4822,17 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
if (ret)
goto err_out_blkdev;
- ret = rbd_bus_add_dev(rbd_dev);
+ ret = rbd_dev_mapping_set(rbd_dev);
if (ret)
goto err_out_disk;
+ set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
+
+ ret = rbd_bus_add_dev(rbd_dev);
+ if (ret)
+ goto err_out_mapping;
/* Everything's ready. Announce the disk to the world. */
- set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
set_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
add_disk(rbd_dev->disk);
@@ -4691,6 +4841,8 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
return ret;
+err_out_mapping:
+ rbd_dev_mapping_clear(rbd_dev);
err_out_disk:
rbd_free_disk(rbd_dev);
err_out_blkdev:
@@ -4731,12 +4883,7 @@ static int rbd_dev_header_name(struct rbd_device *rbd_dev)
static void rbd_dev_image_release(struct rbd_device *rbd_dev)
{
- int ret;
-
rbd_dev_unprobe(rbd_dev);
- ret = rbd_dev_header_watch_sync(rbd_dev, 0);
- if (ret)
- rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret);
kfree(rbd_dev->header_name);
rbd_dev->header_name = NULL;
rbd_dev->image_format = 0;
@@ -4748,18 +4895,20 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev)
/*
* Probe for the existence of the header object for the given rbd
- * device. For format 2 images this includes determining the image
- * id.
+ * device. If this image is the one being mapped (i.e., not a
+ * parent), initiate a watch on its header object before using that
+ * object to get detailed information about the rbd image.
*/
-static int rbd_dev_image_probe(struct rbd_device *rbd_dev)
+static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping)
{
int ret;
int tmp;
/*
- * Get the id from the image id object. If it's not a
- * format 2 image, we'll get ENOENT back, and we'll assume
- * it's a format 1 image.
+ * Get the id from the image id object. Unless there's an
+ * error, rbd_dev->spec->image_id will be filled in with
+ * a dynamically-allocated string, and rbd_dev->image_format
+ * will be set to either 1 or 2.
*/
ret = rbd_dev_image_id(rbd_dev);
if (ret)
@@ -4771,14 +4920,16 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev)
if (ret)
goto err_out_format;
- ret = rbd_dev_header_watch_sync(rbd_dev, 1);
- if (ret)
- goto out_header_name;
+ if (mapping) {
+ ret = rbd_dev_header_watch_sync(rbd_dev, true);
+ if (ret)
+ goto out_header_name;
+ }
if (rbd_dev->image_format == 1)
- ret = rbd_dev_v1_probe(rbd_dev);
+ ret = rbd_dev_v1_header_info(rbd_dev);
else
- ret = rbd_dev_v2_probe(rbd_dev);
+ ret = rbd_dev_v2_header_info(rbd_dev);
if (ret)
goto err_out_watch;
@@ -4787,15 +4938,22 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev)
goto err_out_probe;
ret = rbd_dev_probe_parent(rbd_dev);
- if (!ret)
- return 0;
+ if (ret)
+ goto err_out_probe;
+
+ dout("discovered format %u image, header name is %s\n",
+ rbd_dev->image_format, rbd_dev->header_name);
+ return 0;
err_out_probe:
rbd_dev_unprobe(rbd_dev);
err_out_watch:
- tmp = rbd_dev_header_watch_sync(rbd_dev, 0);
- if (tmp)
- rbd_warn(rbd_dev, "unable to tear down watch request\n");
+ if (mapping) {
+ tmp = rbd_dev_header_watch_sync(rbd_dev, false);
+ if (tmp)
+ rbd_warn(rbd_dev, "unable to tear down "
+ "watch request (%d)\n", tmp);
+ }
out_header_name:
kfree(rbd_dev->header_name);
rbd_dev->header_name = NULL;
@@ -4819,6 +4977,7 @@ static ssize_t rbd_add(struct bus_type *bus,
struct rbd_spec *spec = NULL;
struct rbd_client *rbdc;
struct ceph_osd_client *osdc;
+ bool read_only;
int rc = -ENOMEM;
if (!try_module_get(THIS_MODULE))
@@ -4828,13 +4987,15 @@ static ssize_t rbd_add(struct bus_type *bus,
rc = rbd_add_parse_args(buf, &ceph_opts, &rbd_opts, &spec);
if (rc < 0)
goto err_out_module;
+ read_only = rbd_opts->read_only;
+ kfree(rbd_opts);
+ rbd_opts = NULL; /* done with this */
rbdc = rbd_get_client(ceph_opts);
if (IS_ERR(rbdc)) {
rc = PTR_ERR(rbdc);
goto err_out_args;
}
- ceph_opts = NULL; /* rbd_dev client now owns this */
/* pick the pool */
osdc = &rbdc->client->osdc;
@@ -4858,27 +5019,29 @@ static ssize_t rbd_add(struct bus_type *bus,
rbdc = NULL; /* rbd_dev now owns this */
spec = NULL; /* rbd_dev now owns this */
- rbd_dev->mapping.read_only = rbd_opts->read_only;
- kfree(rbd_opts);
- rbd_opts = NULL; /* done with this */
-
- rc = rbd_dev_image_probe(rbd_dev);
+ rc = rbd_dev_image_probe(rbd_dev, true);
if (rc < 0)
goto err_out_rbd_dev;
+ /* If we are mapping a snapshot it must be marked read-only */
+
+ if (rbd_dev->spec->snap_id != CEPH_NOSNAP)
+ read_only = true;
+ rbd_dev->mapping.read_only = read_only;
+
rc = rbd_dev_device_setup(rbd_dev);
- if (!rc)
- return count;
+ if (rc) {
+ rbd_dev_image_release(rbd_dev);
+ goto err_out_module;
+ }
+
+ return count;
- rbd_dev_image_release(rbd_dev);
err_out_rbd_dev:
rbd_dev_destroy(rbd_dev);
err_out_client:
rbd_put_client(rbdc);
err_out_args:
- if (ceph_opts)
- ceph_destroy_options(ceph_opts);
- kfree(rbd_opts);
rbd_spec_put(spec);
err_out_module:
module_put(THIS_MODULE);
@@ -4911,7 +5074,7 @@ static void rbd_dev_device_release(struct device *dev)
rbd_free_disk(rbd_dev);
clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
- rbd_dev_clear_mapping(rbd_dev);
+ rbd_dev_mapping_clear(rbd_dev);
unregister_blkdev(rbd_dev->major, rbd_dev->name);
rbd_dev->major = 0;
rbd_dev_id_put(rbd_dev);
@@ -4978,10 +5141,13 @@ static ssize_t rbd_remove(struct bus_type *bus,
spin_unlock_irq(&rbd_dev->lock);
if (ret < 0)
goto done;
- ret = count;
rbd_bus_del_dev(rbd_dev);
+ ret = rbd_dev_header_watch_sync(rbd_dev, false);
+ if (ret)
+ rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret);
rbd_dev_image_release(rbd_dev);
module_put(THIS_MODULE);
+ ret = count;
done:
mutex_unlock(&ctl_mutex);
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index f8ef15f..3fd130f 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -1160,8 +1160,7 @@ static int ace_probe(struct platform_device *dev)
dev_dbg(&dev->dev, "ace_probe(%p)\n", dev);
/* device id and bus width */
- of_property_read_u32(dev->dev.of_node, "port-number", &id);
- if (id < 0)
+ if (of_property_read_u32(dev->dev.of_node, "port-number", &id))
id = 0;
if (of_find_property(dev->dev.of_node, "8-bit", NULL))
bus_width = ACE_BUS_WIDTH_8;
diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c
index 4ca35e8..19a12ac6 100644
--- a/drivers/char/hw_random/mxc-rnga.c
+++ b/drivers/char/hw_random/mxc-rnga.c
@@ -167,11 +167,6 @@ static int __init mxc_rnga_probe(struct platform_device *pdev)
clk_prepare_enable(mxc_rng->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- err = -ENOENT;
- goto err_region;
- }
-
mxc_rng->mem = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(mxc_rng->mem)) {
err = PTR_ERR(mxc_rng->mem);
@@ -189,7 +184,6 @@ static int __init mxc_rnga_probe(struct platform_device *pdev)
return 0;
err_ioremap:
-err_region:
clk_disable_unprepare(mxc_rng->clk);
out:
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index 749dc16..d2903e7 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -119,11 +119,6 @@ static int omap_rng_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, priv);
priv->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!priv->mem_res) {
- ret = -ENOENT;
- goto err_ioremap;
- }
-
priv->base = devm_ioremap_resource(&pdev->dev, priv->mem_res);
if (IS_ERR(priv->base)) {
ret = PTR_ERR(priv->base);
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index cdd4c09f..a22a7a5 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -95,9 +95,9 @@ struct si_sm_data {
enum bt_states state;
unsigned char seq; /* BT sequence number */
struct si_sm_io *io;
- unsigned char write_data[IPMI_MAX_MSG_LENGTH];
+ unsigned char write_data[IPMI_MAX_MSG_LENGTH + 2]; /* +2 for memcpy */
int write_count;
- unsigned char read_data[IPMI_MAX_MSG_LENGTH];
+ unsigned char read_data[IPMI_MAX_MSG_LENGTH + 2]; /* +2 for memcpy */
int read_count;
int truncated;
long timeout; /* microseconds countdown */
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 9eb360f..d5a5f02 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -837,13 +837,25 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
return ipmi_ioctl(filep, cmd, arg);
}
}
+
+static long unlocked_compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+
+ mutex_lock(&ipmi_mutex);
+ ret = compat_ipmi_ioctl(filep, cmd, arg);
+ mutex_unlock(&ipmi_mutex);
+
+ return ret;
+}
#endif
static const struct file_operations ipmi_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = ipmi_unlocked_ioctl,
#ifdef CONFIG_COMPAT
- .compat_ioctl = compat_ipmi_ioctl,
+ .compat_ioctl = unlocked_compat_ipmi_ioctl,
#endif
.open = ipmi_open,
.release = ipmi_release,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 4d439d2..4445fa1 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -2037,12 +2037,11 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
- entry->name = kmalloc(strlen(name)+1, GFP_KERNEL);
+ entry->name = kstrdup(name, GFP_KERNEL);
if (!entry->name) {
kfree(entry);
return -ENOMEM;
}
- strcpy(entry->name, name);
file = proc_create_data(name, 0, smi->proc_dir, proc_ops, data);
if (!file) {
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 313538a..af4b23f 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -663,8 +663,10 @@ static void handle_transaction_done(struct smi_info *smi_info)
/* We got the flags from the SMI, now handle them. */
smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
if (msg[2] != 0) {
- dev_warn(smi_info->dev, "Could not enable interrupts"
- ", failed get, using polled mode.\n");
+ dev_warn(smi_info->dev,
+ "Couldn't get irq info: %x.\n", msg[2]);
+ dev_warn(smi_info->dev,
+ "Maybe ok, but ipmi might run very slowly.\n");
smi_info->si_state = SI_NORMAL;
} else {
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
@@ -685,10 +687,12 @@ static void handle_transaction_done(struct smi_info *smi_info)
/* We got the flags from the SMI, now handle them. */
smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
- if (msg[2] != 0)
- dev_warn(smi_info->dev, "Could not enable interrupts"
- ", failed set, using polled mode.\n");
- else
+ if (msg[2] != 0) {
+ dev_warn(smi_info->dev,
+ "Couldn't set irq info: %x.\n", msg[2]);
+ dev_warn(smi_info->dev,
+ "Maybe ok, but ipmi might run very slowly.\n");
+ } else
smi_info->interrupt_disabled = 0;
smi_info->si_state = SI_NORMAL;
break;
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index dafd9ac..0913d79 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -622,9 +622,12 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd,
return -EFAULT;
break;
case LPGETSTATUS:
+ if (mutex_lock_interruptible(&lp_table[minor].port_mutex))
+ return -EINTR;
lp_claim_parport_or_block (&lp_table[minor]);
status = r_str(minor);
lp_release_parport (&lp_table[minor]);
+ mutex_unlock(&lp_table[minor].port_mutex);
if (copy_to_user(argp, &status, sizeof(int)))
return -EFAULT;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index cd9a621..35487e8 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -865,16 +865,24 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
if (r->entropy_count / 8 < min + reserved) {
nbytes = 0;
} else {
+ int entropy_count, orig;
+retry:
+ entropy_count = orig = ACCESS_ONCE(r->entropy_count);
/* If limited, never pull more than available */
- if (r->limit && nbytes + reserved >= r->entropy_count / 8)
- nbytes = r->entropy_count/8 - reserved;
-
- if (r->entropy_count / 8 >= nbytes + reserved)
- r->entropy_count -= nbytes*8;
- else
- r->entropy_count = reserved;
+ if (r->limit && nbytes + reserved >= entropy_count / 8)
+ nbytes = entropy_count/8 - reserved;
+
+ if (entropy_count / 8 >= nbytes + reserved) {
+ entropy_count -= nbytes*8;
+ if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
+ goto retry;
+ } else {
+ entropy_count = reserved;
+ if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig)
+ goto retry;
+ }
- if (r->entropy_count < random_write_wakeup_thresh)
+ if (entropy_count < random_write_wakeup_thresh)
wakeup_write = 1;
}
@@ -957,10 +965,23 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
{
ssize_t ret = 0, i;
__u8 tmp[EXTRACT_SIZE];
+ unsigned long flags;
/* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */
- if (fips_enabled && !r->last_data_init)
- nbytes += EXTRACT_SIZE;
+ if (fips_enabled) {
+ spin_lock_irqsave(&r->lock, flags);
+ if (!r->last_data_init) {
+ r->last_data_init = true;
+ spin_unlock_irqrestore(&r->lock, flags);
+ trace_extract_entropy(r->name, EXTRACT_SIZE,
+ r->entropy_count, _RET_IP_);
+ xfer_secondary_pool(r, EXTRACT_SIZE);
+ extract_buf(r, tmp);
+ spin_lock_irqsave(&r->lock, flags);
+ memcpy(r->last_data, tmp, EXTRACT_SIZE);
+ }
+ spin_unlock_irqrestore(&r->lock, flags);
+ }
trace_extract_entropy(r->name, nbytes, r->entropy_count, _RET_IP_);
xfer_secondary_pool(r, nbytes);
@@ -970,19 +991,6 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
extract_buf(r, tmp);
if (fips_enabled) {
- unsigned long flags;
-
-
- /* prime last_data value if need be, per fips 140-2 */
- if (!r->last_data_init) {
- spin_lock_irqsave(&r->lock, flags);
- memcpy(r->last_data, tmp, EXTRACT_SIZE);
- r->last_data_init = true;
- nbytes -= EXTRACT_SIZE;
- spin_unlock_irqrestore(&r->lock, flags);
- extract_buf(r, tmp);
- }
-
spin_lock_irqsave(&r->lock, flags);
if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
panic("Hardware RNG duplicated output!\n");
diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c
index 4945bd3..d5d2e4a 100644
--- a/drivers/char/ttyprintk.c
+++ b/drivers/char/ttyprintk.c
@@ -179,7 +179,6 @@ static int __init ttyprintk_init(void)
{
int ret = -ENOMEM;
- tpk_port.port.ops = &null_ops;
mutex_init(&tpk_port.port_write_mutex);
ttyprintk_driver = tty_alloc_driver(1,
@@ -190,6 +189,7 @@ static int __init ttyprintk_init(void)
return PTR_ERR(ttyprintk_driver);
tty_port_init(&tpk_port.port);
+ tpk_port.port.ops = &null_ops;
ttyprintk_driver->driver_name = "ttyprintk";
ttyprintk_driver->name = "ttyprintk";
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index 8927284..24f5536 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -932,7 +932,7 @@ static unsigned long si5351_clkout_recalc_rate(struct clk_hw *hw,
unsigned char reg;
unsigned char rdiv;
- if (hwdata->num > 5)
+ if (hwdata->num <= 5)
reg = si5351_msynth_params_address(hwdata->num) + 2;
else
reg = SI5351_CLK6_7_OUTPUT_DIVIDER;
@@ -1477,6 +1477,16 @@ static int si5351_i2c_probe(struct i2c_client *client,
return -EINVAL;
}
drvdata->onecell.clks[n] = clk;
+
+ /* set initial clkout rate */
+ if (pdata->clkout[n].rate != 0) {
+ int ret;
+ ret = clk_set_rate(clk, pdata->clkout[n].rate);
+ if (ret != 0) {
+ dev_err(&client->dev, "Cannot set rate : %d\n",
+ ret);
+ }
+ }
}
ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index debf688..553ac35 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -183,7 +183,7 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
writel(divisor, cdev->div_reg);
vt8500_pmc_wait_busy();
- spin_lock_irqsave(cdev->lock, flags);
+ spin_unlock_irqrestore(cdev->lock, flags);
return 0;
}
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index d0e5eed..4faf0af 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -10,6 +10,7 @@
*/
#include <linux/clk.h>
+#include <linux/clk/mxs.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/init.h>
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index d0940e6..3c1f888 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -791,7 +791,8 @@ struct samsung_gate_clock exynos4210_gate_clks[] __initdata = {
GATE(smmu_pcie, "smmu_pcie", "aclk133", GATE_IP_FSYS, 18, 0, 0),
GATE(modemif, "modemif", "aclk100", GATE_IP_PERIL, 28, 0, 0),
GATE(chipid, "chipid", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0),
- GATE(sysreg, "sysreg", "aclk100", E4210_GATE_IP_PERIR, 0, 0, 0),
+ GATE(sysreg, "sysreg", "aclk100", E4210_GATE_IP_PERIR, 0,
+ CLK_IGNORE_UNUSED, 0),
GATE(hdmi_cec, "hdmi_cec", "aclk100", E4210_GATE_IP_PERIR, 11, 0, 0),
GATE(smmu_rotator, "smmu_rotator", "aclk200",
E4210_GATE_IP_IMAGE, 4, 0, 0),
@@ -819,7 +820,8 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
GATE(smmu_mdma, "smmu_mdma", "aclk200", E4X12_GATE_IP_IMAGE, 5, 0, 0),
GATE(mipi_hsi, "mipi_hsi", "aclk133", GATE_IP_FSYS, 10, 0, 0),
GATE(chipid, "chipid", "aclk100", E4X12_GATE_IP_PERIR, 0, 0, 0),
- GATE(sysreg, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1, 0, 0),
+ GATE(sysreg, "sysreg", "aclk100", E4X12_GATE_IP_PERIR, 1,
+ CLK_IGNORE_UNUSED, 0),
GATE(hdmi_cec, "hdmi_cec", "aclk100", E4X12_GATE_IP_PERIR, 11, 0, 0),
GATE(sclk_mdnie0, "sclk_mdnie0", "div_mdnie0",
SRC_MASK_LCD0, 4, CLK_SET_RATE_PARENT, 0),
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 8292a00..075db0c 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -872,6 +872,14 @@ static void __init tegra20_periph_clk_init(void)
struct clk *clk;
int i;
+ /* ac97 */
+ clk = tegra_clk_register_periph_gate("ac97", "pll_a_out0",
+ TEGRA_PERIPH_ON_APB,
+ clk_base, 0, 3, &periph_l_regs,
+ periph_clk_enb_refcnt);
+ clk_register_clkdev(clk, NULL, "tegra20-ac97");
+ clks[ac97] = clk;
+
/* apbdma */
clk = tegra_clk_register_periph_gate("apbdma", "pclk", 0, clk_base,
0, 34, &periph_h_regs,
@@ -1234,9 +1242,6 @@ static __initdata struct tegra_clk_init_table init_table[] = {
{uartc, pll_p, 0, 0},
{uartd, pll_p, 0, 0},
{uarte, pll_p, 0, 0},
- {usbd, clk_max, 12000000, 0},
- {usb2, clk_max, 12000000, 0},
- {usb3, clk_max, 12000000, 0},
{pll_a, clk_max, 56448000, 1},
{pll_a_out0, clk_max, 11289600, 1},
{cdev1, clk_max, 0, 1},
diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c
index bc7e9bd..e364c9d 100644
--- a/drivers/clk/ux500/clk-sysctrl.c
+++ b/drivers/clk/ux500/clk-sysctrl.c
@@ -145,7 +145,13 @@ static struct clk *clk_reg_sysctrl(struct device *dev,
return ERR_PTR(-ENOMEM);
}
- for (i = 0; i < num_parents; i++) {
+ /* set main clock registers */
+ clk->reg_sel[0] = reg_sel[0];
+ clk->reg_bits[0] = reg_bits[0];
+ clk->reg_mask[0] = reg_mask[0];
+
+ /* handle clocks with more than one parent */
+ for (i = 1; i < num_parents; i++) {
clk->reg_sel[i] = reg_sel[i];
clk->reg_bits[i] = reg_bits[i];
clk->reg_mask[i] = reg_mask[i];
diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c
index 0b4f35a..80069c3 100644
--- a/drivers/clk/ux500/u8500_clk.c
+++ b/drivers/clk/ux500/u8500_clk.c
@@ -325,7 +325,7 @@ void u8500_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base,
BIT(0), 0);
clk_register_clkdev(clk, "fsmc", NULL);
- clk_register_clkdev(clk, NULL, "smsc911x");
+ clk_register_clkdev(clk, NULL, "smsc911x.0");
clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base,
BIT(1), 0);
diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c
index 5cf4f46..4f45eee 100644
--- a/drivers/clk/x86/clk-lpt.c
+++ b/drivers/clk/x86/clk-lpt.c
@@ -15,22 +15,29 @@
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/module.h>
+#include <linux/platform_data/clk-lpss.h>
#include <linux/platform_device.h>
#define PRV_CLOCK_PARAMS 0x800
static int lpt_clk_probe(struct platform_device *pdev)
{
+ struct lpss_clk_data *drvdata;
struct clk *clk;
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
/* LPSS free running clock */
- clk = clk_register_fixed_rate(&pdev->dev, "lpss_clk", NULL, CLK_IS_ROOT,
- 100000000);
+ drvdata->name = "lpss_clk";
+ clk = clk_register_fixed_rate(&pdev->dev, drvdata->name, NULL,
+ CLK_IS_ROOT, 100000000);
if (IS_ERR(clk))
return PTR_ERR(clk);
- /* Shared DMA clock */
- clk_register_clkdev(clk, "hclk", "INTL9C60.0.auto");
+ drvdata->clk = clk;
+ platform_set_drvdata(pdev, drvdata);
return 0;
}
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index a1488f5..534fcb8 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -47,7 +47,7 @@ config CPU_FREQ_STAT_DETAILS
choice
prompt "Default CPUFreq governor"
- default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
+ default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ
default CPU_FREQ_DEFAULT_GOV_PERFORMANCE
help
This option sets which CPUFreq governor shall be loaded at
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index f3af18b..6e57543 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -3,16 +3,17 @@
#
config ARM_BIG_LITTLE_CPUFREQ
- tristate
- depends on ARM_CPU_TOPOLOGY
+ tristate "Generic ARM big LITTLE CPUfreq driver"
+ depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK
+ help
+ This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
config ARM_DT_BL_CPUFREQ
- tristate "Generic ARM big LITTLE CPUfreq driver probed via DT"
- select ARM_BIG_LITTLE_CPUFREQ
- depends on OF && HAVE_CLK
+ tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver"
+ depends on ARM_BIG_LITTLE_CPUFREQ && OF
help
- This enables the Generic CPUfreq driver for ARM big.LITTLE platform.
- This gets frequency tables from DT.
+ This enables probing via DT for Generic CPUfreq driver for ARM
+ big.LITTLE platform. This gets frequency tables from DT.
config ARM_EXYNOS_CPUFREQ
bool "SAMSUNG EXYNOS SoCs"
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 2b8a8c3..6bd63d6 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -272,7 +272,7 @@ config X86_LONGHAUL
config X86_E_POWERSAVER
tristate "VIA C7 Enhanced PowerSaver (DANGEROUS)"
select CPU_FREQ_TABLE
- depends on X86_32
+ depends on X86_32 && ACPI_PROCESSOR
help
This adds the CPUFreq driver for VIA C7 processors. However, this driver
does not have any safeguards to prevent operating the CPU out of spec
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 11b8b4b..edc089e 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -347,11 +347,11 @@ static u32 get_cur_val(const struct cpumask *mask)
switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) {
case SYSTEM_INTEL_MSR_CAPABLE:
cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
- cmd.addr.msr.reg = MSR_IA32_PERF_STATUS;
+ cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
break;
case SYSTEM_AMD_MSR_CAPABLE:
cmd.type = SYSTEM_AMD_MSR_CAPABLE;
- cmd.addr.msr.reg = MSR_AMD_PERF_STATUS;
+ cmd.addr.msr.reg = MSR_AMD_PERF_CTL;
break;
case SYSTEM_IO_CAPABLE:
cmd.type = SYSTEM_IO_CAPABLE;
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index dbdf677..5d7f53f 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -40,11 +40,6 @@ static struct clk *clk[MAX_CLUSTERS];
static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
-static int cpu_to_cluster(int cpu)
-{
- return topology_physical_package_id(cpu);
-}
-
static unsigned int bL_cpufreq_get(unsigned int cpu)
{
u32 cur_cluster = cpu_to_cluster(cpu);
@@ -192,7 +187,7 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
- dev_info(cpu_dev, "CPU %d initialized\n", policy->cpu);
+ dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu);
return 0;
}
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h
index 70f18fc..79b2ce1 100644
--- a/drivers/cpufreq/arm_big_little.h
+++ b/drivers/cpufreq/arm_big_little.h
@@ -34,6 +34,11 @@ struct cpufreq_arm_bL_ops {
int (*init_opp_table)(struct device *cpu_dev);
};
+static inline int cpu_to_cluster(int cpu)
+{
+ return topology_physical_package_id(cpu);
+}
+
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
index 44be311..fd9e3ea 100644
--- a/drivers/cpufreq/arm_big_little_dt.c
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -19,69 +19,75 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/opp.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "arm_big_little.h"
-static int dt_init_opp_table(struct device *cpu_dev)
+/* get cpu node with valid operating-points */
+static struct device_node *get_cpu_node_with_valid_op(int cpu)
{
- struct device_node *np, *parent;
- int count = 0, ret;
+ struct device_node *np = NULL, *parent;
+ int count = 0;
parent = of_find_node_by_path("/cpus");
if (!parent) {
pr_err("failed to find OF /cpus\n");
- return -ENOENT;
+ return NULL;
}
for_each_child_of_node(parent, np) {
- if (count++ != cpu_dev->id)
+ if (count++ != cpu)
continue;
if (!of_get_property(np, "operating-points", NULL)) {
- ret = -ENODATA;
- } else {
- cpu_dev->of_node = np;
- ret = of_init_opp_table(cpu_dev);
+ of_node_put(np);
+ np = NULL;
}
- of_node_put(np);
- of_node_put(parent);
- return ret;
+ break;
}
- return -ENODEV;
+ of_node_put(parent);
+ return np;
}
-static int dt_get_transition_latency(struct device *cpu_dev)
+static int dt_init_opp_table(struct device *cpu_dev)
{
- struct device_node *np, *parent;
- u32 transition_latency = CPUFREQ_ETERNAL;
- int count = 0;
+ struct device_node *np;
+ int ret;
- parent = of_find_node_by_path("/cpus");
- if (!parent) {
- pr_err("failed to find OF /cpus\n");
- return -ENOENT;
- }
+ np = get_cpu_node_with_valid_op(cpu_dev->id);
+ if (!np)
+ return -ENODATA;
- for_each_child_of_node(parent, np) {
- if (count++ != cpu_dev->id)
- continue;
+ cpu_dev->of_node = np;
+ ret = of_init_opp_table(cpu_dev);
+ of_node_put(np);
- of_property_read_u32(np, "clock-latency", &transition_latency);
- of_node_put(np);
- of_node_put(parent);
+ return ret;
+}
- return 0;
- }
+static int dt_get_transition_latency(struct device *cpu_dev)
+{
+ struct device_node *np;
+ u32 transition_latency = CPUFREQ_ETERNAL;
+
+ np = get_cpu_node_with_valid_op(cpu_dev->id);
+ if (!np)
+ return CPUFREQ_ETERNAL;
- return -ENODEV;
+ of_property_read_u32(np, "clock-latency", &transition_latency);
+ of_node_put(np);
+
+ pr_debug("%s: clock-latency: %d\n", __func__, transition_latency);
+ return transition_latency;
}
static struct cpufreq_arm_bL_ops dt_bL_ops = {
@@ -90,17 +96,33 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = {
.init_opp_table = dt_init_opp_table,
};
-static int generic_bL_init(void)
+static int generic_bL_probe(struct platform_device *pdev)
{
+ struct device_node *np;
+
+ np = get_cpu_node_with_valid_op(0);
+ if (!np)
+ return -ENODEV;
+
+ of_node_put(np);
return bL_cpufreq_register(&dt_bL_ops);
}
-module_init(generic_bL_init);
-static void generic_bL_exit(void)
+static int generic_bL_remove(struct platform_device *pdev)
{
- return bL_cpufreq_unregister(&dt_bL_ops);
+ bL_cpufreq_unregister(&dt_bL_ops);
+ return 0;
}
-module_exit(generic_bL_exit);
+
+static struct platform_driver generic_bL_platdrv = {
+ .driver = {
+ .name = "arm-bL-cpufreq-dt",
+ .owner = THIS_MODULE,
+ },
+ .probe = generic_bL_probe,
+ .remove = generic_bL_remove,
+};
+module_platform_driver(generic_bL_platdrv);
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
MODULE_DESCRIPTION("Generic ARM big LITTLE cpufreq driver via DT");
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index 3ab8294..ad1fde2 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -45,7 +45,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
struct cpufreq_freqs freqs;
struct opp *opp;
unsigned long volt = 0, volt_old = 0, tol = 0;
- long freq_Hz;
+ long freq_Hz, freq_exact;
unsigned int index;
int ret;
@@ -60,6 +60,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
if (freq_Hz < 0)
freq_Hz = freq_table[index].frequency * 1000;
+ freq_exact = freq_Hz;
freqs.new = freq_Hz / 1000;
freqs.old = clk_get_rate(cpu_clk) / 1000;
@@ -98,7 +99,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy,
}
}
- ret = clk_set_rate(cpu_clk, freqs.new * 1000);
+ ret = clk_set_rate(cpu_clk, freq_exact);
if (ret) {
pr_err("failed to set clock rate: %d\n", ret);
if (cpu_reg)
@@ -189,12 +190,29 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
if (!np) {
pr_err("failed to find cpu0 node\n");
- return -ENOENT;
+ ret = -ENOENT;
+ goto out_put_parent;
}
cpu_dev = &pdev->dev;
cpu_dev->of_node = np;
+ cpu_reg = devm_regulator_get(cpu_dev, "cpu0");
+ if (IS_ERR(cpu_reg)) {
+ /*
+ * If cpu0 regulator supply node is present, but regulator is
+ * not yet registered, we should try defering probe.
+ */
+ if (PTR_ERR(cpu_reg) == -EPROBE_DEFER) {
+ dev_err(cpu_dev, "cpu0 regulator not ready, retry\n");
+ ret = -EPROBE_DEFER;
+ goto out_put_node;
+ }
+ pr_warn("failed to get cpu0 regulator: %ld\n",
+ PTR_ERR(cpu_reg));
+ cpu_reg = NULL;
+ }
+
cpu_clk = devm_clk_get(cpu_dev, NULL);
if (IS_ERR(cpu_clk)) {
ret = PTR_ERR(cpu_clk);
@@ -202,12 +220,6 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
goto out_put_node;
}
- cpu_reg = devm_regulator_get(cpu_dev, "cpu0");
- if (IS_ERR(cpu_reg)) {
- pr_warn("failed to get cpu0 regulator\n");
- cpu_reg = NULL;
- }
-
ret = of_init_opp_table(cpu_dev);
if (ret) {
pr_err("failed to init OPP table: %d\n", ret);
@@ -264,6 +276,8 @@ out_free_table:
opp_free_cpufreq_table(cpu_dev, &freq_table);
out_put_node:
of_node_put(np);
+out_put_parent:
+ of_node_put(parent);
return ret;
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 1b8a48e..2d53f47 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -1075,14 +1075,14 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
__func__, cpu_dev->id, cpu);
}
+ if ((cpus == 1) && (cpufreq_driver->target))
+ __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
+
pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
cpufreq_cpu_put(data);
/* If cpu is last user of policy, free policy */
if (cpus == 1) {
- if (cpufreq_driver->target)
- __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
-
lock_policy_rwsem_read(cpu);
kobj = &data->kobj;
cmp = &data->kobj_unregister;
@@ -1729,18 +1729,23 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
/* end old governor */
if (data->governor) {
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
+ unlock_policy_rwsem_write(policy->cpu);
__cpufreq_governor(data,
CPUFREQ_GOV_POLICY_EXIT);
+ lock_policy_rwsem_write(policy->cpu);
}
/* start new governor */
data->governor = policy->governor;
if (!__cpufreq_governor(data, CPUFREQ_GOV_POLICY_INIT)) {
- if (!__cpufreq_governor(data, CPUFREQ_GOV_START))
+ if (!__cpufreq_governor(data, CPUFREQ_GOV_START)) {
failed = 0;
- else
+ } else {
+ unlock_policy_rwsem_write(policy->cpu);
__cpufreq_governor(data,
CPUFREQ_GOV_POLICY_EXIT);
+ lock_policy_rwsem_write(policy->cpu);
+ }
}
if (failed) {
@@ -1832,15 +1837,13 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
if (dev) {
switch (action) {
case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
cpufreq_add_dev(dev, NULL);
break;
case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
+ case CPU_UP_CANCELED_FROZEN:
__cpufreq_remove_dev(dev, NULL);
break;
case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
cpufreq_add_dev(dev, NULL);
break;
}
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 443442d..dc9b72e 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -26,6 +26,7 @@
#include <linux/tick.h>
#include <linux/types.h>
#include <linux/workqueue.h>
+#include <linux/cpu.h>
#include "cpufreq_governor.h"
@@ -180,8 +181,10 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
if (!all_cpus) {
__gov_queue_work(smp_processor_id(), dbs_data, delay);
} else {
+ get_online_cpus();
for_each_cpu(i, policy->cpus)
__gov_queue_work(i, dbs_data, delay);
+ put_online_cpus();
}
}
EXPORT_SYMBOL_GPL(gov_queue_work);
@@ -255,6 +258,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
if (have_governor_per_policy()) {
WARN_ON(dbs_data);
} else if (dbs_data) {
+ dbs_data->usage_count++;
policy->governor_data = dbs_data;
return 0;
}
@@ -266,6 +270,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
}
dbs_data->cdata = cdata;
+ dbs_data->usage_count = 1;
rc = cdata->init(dbs_data);
if (rc) {
pr_err("%s: POLICY_INIT: init() failed\n", __func__);
@@ -294,7 +299,8 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
set_sampling_rate(dbs_data, max(dbs_data->min_sampling_rate,
latency * LATENCY_MULTIPLIER));
- if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
+ if ((cdata->governor == GOV_CONSERVATIVE) &&
+ (!policy->governor->initialized)) {
struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
cpufreq_register_notifier(cs_ops->notifier_block,
@@ -306,12 +312,12 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return 0;
case CPUFREQ_GOV_POLICY_EXIT:
- if ((policy->governor->initialized == 1) ||
- have_governor_per_policy()) {
+ if (!--dbs_data->usage_count) {
sysfs_remove_group(get_governor_parent_kobj(policy),
get_sysfs_attr(dbs_data));
- if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
+ if ((dbs_data->cdata->governor == GOV_CONSERVATIVE) &&
+ (policy->governor->initialized == 1)) {
struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
cpufreq_unregister_notifier(cs_ops->notifier_block,
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index 8ac3353..e16a961 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -211,6 +211,7 @@ struct common_dbs_data {
struct dbs_data {
struct common_dbs_data *cdata;
unsigned int min_sampling_rate;
+ int usage_count;
void *tuners;
/* dbs_mutex protects dbs_enable in governor start/stop */
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index b0ffef9..4b9bb5d 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -547,7 +547,6 @@ static int od_init(struct dbs_data *dbs_data)
tuners->io_is_busy = should_io_be_busy();
dbs_data->tuners = tuners;
- pr_info("%s: tuners %p\n", __func__, tuners);
mutex_init(&dbs_data->mutex);
return 0;
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index bfd6273..fb65dec 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -349,15 +349,16 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu);
break;
case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
cpufreq_stats_free_sysfs(cpu);
break;
case CPU_DEAD:
- case CPU_DEAD_FROZEN:
+ cpufreq_stats_free_table(cpu);
+ break;
+ case CPU_UP_CANCELED_FROZEN:
+ cpufreq_stats_free_sysfs(cpu);
cpufreq_stats_free_table(cpu);
break;
}
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index cc3a8e6..07f2840 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -48,12 +48,7 @@ static inline int32_t div_fp(int32_t x, int32_t y)
}
struct sample {
- ktime_t start_time;
- ktime_t end_time;
int core_pct_busy;
- int pstate_pct_busy;
- u64 duration_us;
- u64 idletime_us;
u64 aperf;
u64 mperf;
int freq;
@@ -86,13 +81,9 @@ struct cpudata {
struct pstate_adjust_policy *pstate_policy;
struct pstate_data pstate;
struct _pid pid;
- struct _pid idle_pid;
int min_pstate_count;
- int idle_mode;
- ktime_t prev_sample;
- u64 prev_idle_time_us;
u64 prev_aperf;
u64 prev_mperf;
int sample_ptr;
@@ -124,6 +115,8 @@ struct perf_limits {
int min_perf_pct;
int32_t max_perf;
int32_t min_perf;
+ int max_policy_pct;
+ int max_sysfs_pct;
};
static struct perf_limits limits = {
@@ -132,6 +125,8 @@ static struct perf_limits limits = {
.max_perf = int_tofp(1),
.min_perf_pct = 0,
.min_perf = 0,
+ .max_policy_pct = 100,
+ .max_sysfs_pct = 100,
};
static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
@@ -202,19 +197,6 @@ static inline void intel_pstate_busy_pid_reset(struct cpudata *cpu)
0);
}
-static inline void intel_pstate_idle_pid_reset(struct cpudata *cpu)
-{
- pid_p_gain_set(&cpu->idle_pid, cpu->pstate_policy->p_gain_pct);
- pid_d_gain_set(&cpu->idle_pid, cpu->pstate_policy->d_gain_pct);
- pid_i_gain_set(&cpu->idle_pid, cpu->pstate_policy->i_gain_pct);
-
- pid_reset(&cpu->idle_pid,
- 75,
- 50,
- cpu->pstate_policy->deadband,
- 0);
-}
-
static inline void intel_pstate_reset_all_pid(void)
{
unsigned int cpu;
@@ -302,7 +284,8 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
if (ret != 1)
return -EINVAL;
- limits.max_perf_pct = clamp_t(int, input, 0 , 100);
+ limits.max_sysfs_pct = clamp_t(int, input, 0 , 100);
+ limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
return count;
}
@@ -408,9 +391,8 @@ static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate)
if (pstate == cpu->pstate.current_pstate)
return;
-#ifndef MODULE
trace_cpu_frequency(pstate * 100000, cpu->cpu);
-#endif
+
cpu->pstate.current_pstate = pstate;
wrmsrl(MSR_IA32_PERF_CTL, pstate << 8);
@@ -450,48 +432,26 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu,
struct sample *sample)
{
u64 core_pct;
- sample->pstate_pct_busy = 100 - div64_u64(
- sample->idletime_us * 100,
- sample->duration_us);
core_pct = div64_u64(sample->aperf * 100, sample->mperf);
sample->freq = cpu->pstate.max_pstate * core_pct * 1000;
- sample->core_pct_busy = div_s64((sample->pstate_pct_busy * core_pct),
- 100);
+ sample->core_pct_busy = core_pct;
}
static inline void intel_pstate_sample(struct cpudata *cpu)
{
- ktime_t now;
- u64 idle_time_us;
u64 aperf, mperf;
- now = ktime_get();
- idle_time_us = get_cpu_idle_time_us(cpu->cpu, NULL);
-
rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf);
- /* for the first sample, don't actually record a sample, just
- * set the baseline */
- if (cpu->prev_idle_time_us > 0) {
- cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
- cpu->samples[cpu->sample_ptr].start_time = cpu->prev_sample;
- cpu->samples[cpu->sample_ptr].end_time = now;
- cpu->samples[cpu->sample_ptr].duration_us =
- ktime_us_delta(now, cpu->prev_sample);
- cpu->samples[cpu->sample_ptr].idletime_us =
- idle_time_us - cpu->prev_idle_time_us;
-
- cpu->samples[cpu->sample_ptr].aperf = aperf;
- cpu->samples[cpu->sample_ptr].mperf = mperf;
- cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf;
- cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf;
-
- intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
- }
+ cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
+ cpu->samples[cpu->sample_ptr].aperf = aperf;
+ cpu->samples[cpu->sample_ptr].mperf = mperf;
+ cpu->samples[cpu->sample_ptr].aperf -= cpu->prev_aperf;
+ cpu->samples[cpu->sample_ptr].mperf -= cpu->prev_mperf;
+
+ intel_pstate_calc_busy(cpu, &cpu->samples[cpu->sample_ptr]);
- cpu->prev_sample = now;
- cpu->prev_idle_time_us = idle_time_us;
cpu->prev_aperf = aperf;
cpu->prev_mperf = mperf;
}
@@ -505,16 +465,6 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
mod_timer_pinned(&cpu->timer, jiffies + delay);
}
-static inline void intel_pstate_idle_mode(struct cpudata *cpu)
-{
- cpu->idle_mode = 1;
-}
-
-static inline void intel_pstate_normal_mode(struct cpudata *cpu)
-{
- cpu->idle_mode = 0;
-}
-
static inline int intel_pstate_get_scaled_busy(struct cpudata *cpu)
{
int32_t busy_scaled;
@@ -547,50 +497,21 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
intel_pstate_pstate_decrease(cpu, steps);
}
-static inline void intel_pstate_adjust_idle_pstate(struct cpudata *cpu)
-{
- int busy_scaled;
- struct _pid *pid;
- int ctl = 0;
- int steps;
-
- pid = &cpu->idle_pid;
-
- busy_scaled = intel_pstate_get_scaled_busy(cpu);
-
- ctl = pid_calc(pid, 100 - busy_scaled);
-
- steps = abs(ctl);
- if (ctl < 0)
- intel_pstate_pstate_decrease(cpu, steps);
- else
- intel_pstate_pstate_increase(cpu, steps);
-
- if (cpu->pstate.current_pstate == cpu->pstate.min_pstate)
- intel_pstate_normal_mode(cpu);
-}
-
static void intel_pstate_timer_func(unsigned long __data)
{
struct cpudata *cpu = (struct cpudata *) __data;
intel_pstate_sample(cpu);
+ intel_pstate_adjust_busy_pstate(cpu);
- if (!cpu->idle_mode)
- intel_pstate_adjust_busy_pstate(cpu);
- else
- intel_pstate_adjust_idle_pstate(cpu);
-
-#if defined(XPERF_FIX)
if (cpu->pstate.current_pstate == cpu->pstate.min_pstate) {
cpu->min_pstate_count++;
if (!(cpu->min_pstate_count % 5)) {
intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
- intel_pstate_idle_mode(cpu);
}
} else
cpu->min_pstate_count = 0;
-#endif
+
intel_pstate_set_sample_time(cpu);
}
@@ -600,6 +521,7 @@ static void intel_pstate_timer_func(unsigned long __data)
static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(0x2a, default_policy),
ICPU(0x2d, default_policy),
+ ICPU(0x3a, default_policy),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
@@ -631,7 +553,6 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
(unsigned long)cpu;
cpu->timer.expires = jiffies + HZ/100;
intel_pstate_busy_pid_reset(cpu);
- intel_pstate_idle_pid_reset(cpu);
intel_pstate_sample(cpu);
intel_pstate_set_pstate(cpu, cpu->pstate.max_pstate);
@@ -675,8 +596,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
- limits.max_perf_pct = policy->max * 100 / policy->cpuinfo.max_freq;
- limits.max_perf_pct = clamp_t(int, limits.max_perf_pct, 0 , 100);
+ limits.max_policy_pct = policy->max * 100 / policy->cpuinfo.max_freq;
+ limits.max_policy_pct = clamp_t(int, limits.max_policy_pct, 0 , 100);
+ limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
return 0;
@@ -788,10 +710,9 @@ static int __init intel_pstate_init(void)
pr_info("Intel P-state driver initializing.\n");
- all_cpu_data = vmalloc(sizeof(void *) * num_possible_cpus());
+ all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus());
if (!all_cpu_data)
return -ENOMEM;
- memset(all_cpu_data, 0, sizeof(void *) * num_possible_cpus());
rc = cpufreq_register_driver(&intel_pstate_driver);
if (rc)
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index d36ea8d..b2644af 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -171,10 +171,6 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev)
priv.dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Cannot get memory resource\n");
- return -ENODEV;
- }
priv.base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv.base))
return PTR_ERR(priv.base);
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index 8488957..d539127 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <asm/clock.h>
+#include <asm/idle.h>
#include <asm/mach-loongson/loongson.h>
@@ -200,6 +201,7 @@ static void loongson2_cpu_wait(void)
LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */
LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */
spin_unlock_irqrestore(&loongson2_wait_lock, flags);
+ local_irq_enable();
}
static int __init cpufreq_init(void)
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 765fdf5..bf416a8 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -1154,7 +1154,7 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
dst_nents = sg_count(req->dst, req->cryptlen, &dst_chained);
sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1,
- DMA_BIDIRECTIONAL, assoc_chained);
+ DMA_TO_DEVICE, assoc_chained);
if (likely(req->src == req->dst)) {
sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1,
DMA_BIDIRECTIONAL, src_chained);
@@ -1336,7 +1336,7 @@ static struct aead_edesc *aead_giv_edesc_alloc(struct aead_givcrypt_request
dst_nents = sg_count(req->dst, req->cryptlen, &dst_chained);
sgc = dma_map_sg_chained(jrdev, req->assoc, assoc_nents ? : 1,
- DMA_BIDIRECTIONAL, assoc_chained);
+ DMA_TO_DEVICE, assoc_chained);
if (likely(req->src == req->dst)) {
sgc = dma_map_sg_chained(jrdev, req->src, src_nents ? : 1,
DMA_BIDIRECTIONAL, src_chained);
diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c
index a76d4c4..35d483f 100644
--- a/drivers/crypto/nx/nx-aes-cbc.c
+++ b/drivers/crypto/nx/nx-aes-cbc.c
@@ -126,6 +126,7 @@ struct crypto_alg nx_cbc_aes_alg = {
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct nx_crypto_ctx),
.cra_type = &crypto_blkcipher_type,
+ .cra_alignmask = 0xf,
.cra_module = THIS_MODULE,
.cra_init = nx_crypto_ctx_aes_cbc_init,
.cra_exit = nx_crypto_ctx_exit,
diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c
index ba5f161..7bbc9a8 100644
--- a/drivers/crypto/nx/nx-aes-ecb.c
+++ b/drivers/crypto/nx/nx-aes-ecb.c
@@ -123,6 +123,7 @@ struct crypto_alg nx_ecb_aes_alg = {
.cra_priority = 300,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
+ .cra_alignmask = 0xf,
.cra_ctxsize = sizeof(struct nx_crypto_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
index c8109ed..6cca6c3 100644
--- a/drivers/crypto/nx/nx-aes-gcm.c
+++ b/drivers/crypto/nx/nx-aes-gcm.c
@@ -219,7 +219,7 @@ static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
if (enc)
NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
else
- nbytes -= AES_BLOCK_SIZE;
+ nbytes -= crypto_aead_authsize(crypto_aead_reqtfm(req));
csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8;
diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c
index 9767315..67024f2 100644
--- a/drivers/crypto/nx/nx-sha256.c
+++ b/drivers/crypto/nx/nx-sha256.c
@@ -69,7 +69,7 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
* 1: <= SHA256_BLOCK_SIZE: copy into state, return 0
* 2: > SHA256_BLOCK_SIZE: process X blocks, copy in leftover
*/
- if (len + sctx->count <= SHA256_BLOCK_SIZE) {
+ if (len + sctx->count < SHA256_BLOCK_SIZE) {
memcpy(sctx->buf + sctx->count, data, len);
sctx->count += len;
goto out;
@@ -110,7 +110,8 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
atomic_inc(&(nx_ctx->stats->sha256_ops));
/* copy the leftover back into the state struct */
- memcpy(sctx->buf, data + len - leftover, leftover);
+ if (leftover)
+ memcpy(sctx->buf, data + len - leftover, leftover);
sctx->count = leftover;
csbcpb->cpb.sha256.message_bit_length += (u64)
@@ -130,6 +131,7 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out)
struct nx_sg *in_sg, *out_sg;
int rc;
+
if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
/* we've hit the nx chip previously, now we're finalizing,
* so copy over the partial digest */
@@ -162,7 +164,7 @@ static int nx_sha256_final(struct shash_desc *desc, u8 *out)
atomic_inc(&(nx_ctx->stats->sha256_ops));
- atomic64_add(csbcpb->cpb.sha256.message_bit_length,
+ atomic64_add(csbcpb->cpb.sha256.message_bit_length / 8,
&(nx_ctx->stats->sha256_bytes));
memcpy(out, csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
out:
diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c
index 3177b8c..08eee11 100644
--- a/drivers/crypto/nx/nx-sha512.c
+++ b/drivers/crypto/nx/nx-sha512.c
@@ -69,7 +69,7 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
* 1: <= SHA512_BLOCK_SIZE: copy into state, return 0
* 2: > SHA512_BLOCK_SIZE: process X blocks, copy in leftover
*/
- if ((u64)len + sctx->count[0] <= SHA512_BLOCK_SIZE) {
+ if ((u64)len + sctx->count[0] < SHA512_BLOCK_SIZE) {
memcpy(sctx->buf + sctx->count[0], data, len);
sctx->count[0] += len;
goto out;
@@ -110,7 +110,8 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
atomic_inc(&(nx_ctx->stats->sha512_ops));
/* copy the leftover back into the state struct */
- memcpy(sctx->buf, data + len - leftover, leftover);
+ if (leftover)
+ memcpy(sctx->buf, data + len - leftover, leftover);
sctx->count[0] = leftover;
spbc_bits = csbcpb->cpb.sha512.spbc * 8;
@@ -168,7 +169,7 @@ static int nx_sha512_final(struct shash_desc *desc, u8 *out)
goto out;
atomic_inc(&(nx_ctx->stats->sha512_ops));
- atomic64_add(csbcpb->cpb.sha512.message_bit_length_lo,
+ atomic64_add(csbcpb->cpb.sha512.message_bit_length_lo / 8,
&(nx_ctx->stats->sha512_bytes));
memcpy(out, csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
index c767f23..bbdab6e 100644
--- a/drivers/crypto/nx/nx.c
+++ b/drivers/crypto/nx/nx.c
@@ -211,44 +211,20 @@ int nx_build_sg_lists(struct nx_crypto_ctx *nx_ctx,
{
struct nx_sg *nx_insg = nx_ctx->in_sg;
struct nx_sg *nx_outsg = nx_ctx->out_sg;
- struct blkcipher_walk walk;
- int rc;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- rc = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
- if (rc)
- goto out;
if (iv)
- memcpy(iv, walk.iv, AES_BLOCK_SIZE);
+ memcpy(iv, desc->info, AES_BLOCK_SIZE);
- while (walk.nbytes) {
- nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
- walk.nbytes, nx_ctx->ap->sglen);
- nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
- walk.nbytes, nx_ctx->ap->sglen);
-
- rc = blkcipher_walk_done(desc, &walk, 0);
- if (rc)
- break;
- }
-
- if (walk.nbytes) {
- nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
- walk.nbytes, nx_ctx->ap->sglen);
- nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
- walk.nbytes, nx_ctx->ap->sglen);
-
- rc = 0;
- }
+ nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen, src, 0, nbytes);
+ nx_outsg = nx_walk_and_build(nx_outsg, nx_ctx->ap->sglen, dst, 0, nbytes);
/* these lengths should be negative, which will indicate to phyp that
* the input and output parameters are scatterlists, not linear
* buffers */
nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * sizeof(struct nx_sg);
nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) * sizeof(struct nx_sg);
-out:
- return rc;
+
+ return 0;
}
/**
@@ -454,6 +430,8 @@ static int nx_register_algs(void)
if (rc)
goto out;
+ nx_driver.of.status = NX_OKAY;
+
rc = crypto_register_alg(&nx_ecb_aes_alg);
if (rc)
goto out;
@@ -498,8 +476,6 @@ static int nx_register_algs(void)
if (rc)
goto out_unreg_s512;
- nx_driver.of.status = NX_OKAY;
-
goto out;
out_unreg_s512:
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index a97bb6c..c3dc1c0 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -863,7 +863,7 @@ static struct of_device_id sahara_dt_ids[] = {
{ .compatible = "fsl,imx27-sahara" },
{ /* sentinel */ }
};
-MODULE_DEVICE_TABLE(platform, sahara_dt_ids);
+MODULE_DEVICE_TABLE(of, sahara_dt_ids);
static int sahara_probe(struct platform_device *pdev)
{
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
index ba6fc62..5a18f82 100644
--- a/drivers/dma/acpi-dma.c
+++ b/drivers/dma/acpi-dma.c
@@ -4,7 +4,8 @@
* Based on of-dma.c
*
* Copyright (C) 2013, Intel Corporation
- * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ * Mika Westerberg <mika.westerberg@linux.intel.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
@@ -16,6 +17,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/ioport.h>
#include <linux/acpi.h>
#include <linux/acpi_dma.h>
@@ -23,6 +25,117 @@ static LIST_HEAD(acpi_dma_list);
static DEFINE_MUTEX(acpi_dma_lock);
/**
+ * acpi_dma_parse_resource_group - match device and parse resource group
+ * @grp: CSRT resource group
+ * @adev: ACPI device to match with
+ * @adma: struct acpi_dma of the given DMA controller
+ *
+ * Returns 1 on success, 0 when no information is available, or appropriate
+ * errno value on error.
+ *
+ * In order to match a device from DSDT table to the corresponding CSRT device
+ * we use MMIO address and IRQ.
+ */
+static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
+ struct acpi_device *adev, struct acpi_dma *adma)
+{
+ const struct acpi_csrt_shared_info *si;
+ struct list_head resource_list;
+ struct resource_list_entry *rentry;
+ resource_size_t mem = 0, irq = 0;
+ u32 vendor_id;
+ int ret;
+
+ if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
+ return -ENODEV;
+
+ INIT_LIST_HEAD(&resource_list);
+ ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+ if (ret <= 0)
+ return 0;
+
+ list_for_each_entry(rentry, &resource_list, node) {
+ if (resource_type(&rentry->res) == IORESOURCE_MEM)
+ mem = rentry->res.start;
+ else if (resource_type(&rentry->res) == IORESOURCE_IRQ)
+ irq = rentry->res.start;
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ /* Consider initial zero values as resource not found */
+ if (mem == 0 && irq == 0)
+ return 0;
+
+ si = (const struct acpi_csrt_shared_info *)&grp[1];
+
+ /* Match device by MMIO and IRQ */
+ if (si->mmio_base_low != mem || si->gsi_interrupt != irq)
+ return 0;
+
+ vendor_id = le32_to_cpu(grp->vendor_id);
+ dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n",
+ (char *)&vendor_id, grp->device_id, grp->revision);
+
+ /* Check if the request line range is available */
+ if (si->base_request_line == 0 && si->num_handshake_signals == 0)
+ return 0;
+
+ adma->base_request_line = si->base_request_line;
+ adma->end_request_line = si->base_request_line +
+ si->num_handshake_signals - 1;
+
+ dev_dbg(&adev->dev, "request line base: 0x%04x end: 0x%04x\n",
+ adma->base_request_line, adma->end_request_line);
+
+ return 1;
+}
+
+/**
+ * acpi_dma_parse_csrt - parse CSRT to exctract additional DMA resources
+ * @adev: ACPI device to match with
+ * @adma: struct acpi_dma of the given DMA controller
+ *
+ * CSRT or Core System Resources Table is a proprietary ACPI table
+ * introduced by Microsoft. This table can contain devices that are not in
+ * the system DSDT table. In particular DMA controllers might be described
+ * here.
+ *
+ * We are using this table to get the request line range of the specific DMA
+ * controller to be used later.
+ *
+ */
+static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
+{
+ struct acpi_csrt_group *grp, *end;
+ struct acpi_table_csrt *csrt;
+ acpi_status status;
+ int ret;
+
+ status = acpi_get_table(ACPI_SIG_CSRT, 0,
+ (struct acpi_table_header **)&csrt);
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND)
+ dev_warn(&adev->dev, "failed to get the CSRT table\n");
+ return;
+ }
+
+ grp = (struct acpi_csrt_group *)(csrt + 1);
+ end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length);
+
+ while (grp < end) {
+ ret = acpi_dma_parse_resource_group(grp, adev, adma);
+ if (ret < 0) {
+ dev_warn(&adev->dev,
+ "error in parsing resource group\n");
+ return;
+ }
+
+ grp = (struct acpi_csrt_group *)((void *)grp + grp->length);
+ }
+}
+
+/**
* acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers
* @dev: struct device of DMA controller
* @acpi_dma_xlate: translation function which converts a dma specifier
@@ -61,6 +174,8 @@ int acpi_dma_controller_register(struct device *dev,
adma->acpi_dma_xlate = acpi_dma_xlate;
adma->data = data;
+ acpi_dma_parse_csrt(adev, adma);
+
/* Now queue acpi_dma controller structure in list */
mutex_lock(&acpi_dma_lock);
list_add_tail(&adma->dma_controllers, &acpi_dma_list);
@@ -149,6 +264,45 @@ void devm_acpi_dma_controller_free(struct device *dev)
}
EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
+/**
+ * acpi_dma_update_dma_spec - prepare dma specifier to pass to translation function
+ * @adma: struct acpi_dma of DMA controller
+ * @dma_spec: dma specifier to update
+ *
+ * Returns 0, if no information is avaiable, -1 on mismatch, and 1 otherwise.
+ *
+ * Accordingly to ACPI 5.0 Specification Table 6-170 "Fixed DMA Resource
+ * Descriptor":
+ * DMA Request Line bits is a platform-relative number uniquely
+ * identifying the request line assigned. Request line-to-Controller
+ * mapping is done in a controller-specific OS driver.
+ * That's why we can safely adjust slave_id when the appropriate controller is
+ * found.
+ */
+static int acpi_dma_update_dma_spec(struct acpi_dma *adma,
+ struct acpi_dma_spec *dma_spec)
+{
+ /* Set link to the DMA controller device */
+ dma_spec->dev = adma->dev;
+
+ /* Check if the request line range is available */
+ if (adma->base_request_line == 0 && adma->end_request_line == 0)
+ return 0;
+
+ /* Check if slave_id falls to the range */
+ if (dma_spec->slave_id < adma->base_request_line ||
+ dma_spec->slave_id > adma->end_request_line)
+ return -1;
+
+ /*
+ * Here we adjust slave_id. It should be a relative number to the base
+ * request line.
+ */
+ dma_spec->slave_id -= adma->base_request_line;
+
+ return 1;
+}
+
struct acpi_dma_parser_data {
struct acpi_dma_spec dma_spec;
size_t index;
@@ -193,6 +347,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
struct acpi_device *adev;
struct acpi_dma *adma;
struct dma_chan *chan = NULL;
+ int found;
/* Check if the device was enumerated by ACPI */
if (!dev || !ACPI_HANDLE(dev))
@@ -219,9 +374,20 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
mutex_lock(&acpi_dma_lock);
list_for_each_entry(adma, &acpi_dma_list, dma_controllers) {
- dma_spec->dev = adma->dev;
+ /*
+ * We are not going to call translation function if slave_id
+ * doesn't fall to the request range.
+ */
+ found = acpi_dma_update_dma_spec(adma, dma_spec);
+ if (found < 0)
+ continue;
chan = adma->acpi_dma_xlate(dma_spec, adma);
- if (chan)
+ /*
+ * Try to get a channel only from the DMA controller that
+ * matches the slave_id. See acpi_dma_update_dma_spec()
+ * description for the details.
+ */
+ if (found > 0 || chan)
break;
}
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index d8ce4ec..e88ded2 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -716,8 +716,7 @@ static int dmatest_func(void *data)
}
dma_async_issue_pending(chan);
- wait_event_freezable_timeout(done_wait,
- done.done || kthread_should_stop(),
+ wait_event_freezable_timeout(done_wait, done.done,
msecs_to_jiffies(params->timeout));
status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
@@ -997,7 +996,6 @@ static void stop_threaded_test(struct dmatest_info *info)
static int __restart_threaded_test(struct dmatest_info *info, bool run)
{
struct dmatest_params *params = &info->params;
- int ret;
/* Stop any running test first */
__stop_threaded_test(info);
@@ -1012,13 +1010,23 @@ static int __restart_threaded_test(struct dmatest_info *info, bool run)
memcpy(params, &info->dbgfs_params, sizeof(*params));
/* Run test with new parameters */
- ret = __run_threaded_test(info);
- if (ret) {
- __stop_threaded_test(info);
- pr_err("dmatest: Can't run test\n");
+ return __run_threaded_test(info);
+}
+
+static bool __is_threaded_test_run(struct dmatest_info *info)
+{
+ struct dmatest_chan *dtc;
+
+ list_for_each_entry(dtc, &info->channels, node) {
+ struct dmatest_thread *thread;
+
+ list_for_each_entry(thread, &dtc->threads, node) {
+ if (!thread->done)
+ return true;
+ }
}
- return ret;
+ return false;
}
static ssize_t dtf_write_string(void *to, size_t available, loff_t *ppos,
@@ -1091,22 +1099,10 @@ static ssize_t dtf_read_run(struct file *file, char __user *user_buf,
{
struct dmatest_info *info = file->private_data;
char buf[3];
- struct dmatest_chan *dtc;
- bool alive = false;
mutex_lock(&info->lock);
- list_for_each_entry(dtc, &info->channels, node) {
- struct dmatest_thread *thread;
-
- list_for_each_entry(thread, &dtc->threads, node) {
- if (!thread->done) {
- alive = true;
- break;
- }
- }
- }
- if (alive) {
+ if (__is_threaded_test_run(info)) {
buf[0] = 'Y';
} else {
__stop_threaded_test(info);
@@ -1132,7 +1128,12 @@ static ssize_t dtf_write_run(struct file *file, const char __user *user_buf,
if (strtobool(buf, &bv) == 0) {
mutex_lock(&info->lock);
- ret = __restart_threaded_test(info, bv);
+
+ if (__is_threaded_test_run(info))
+ ret = -EBUSY;
+ else
+ ret = __restart_threaded_test(info, bv);
+
mutex_unlock(&info->lock);
}
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 1734fee..71bf4ec 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1566,10 +1566,12 @@ static void dma_tc_handle(struct d40_chan *d40c)
return;
}
- if (d40_queue_start(d40c) == NULL)
+ if (d40_queue_start(d40c) == NULL) {
d40c->busy = false;
- pm_runtime_mark_last_busy(d40c->base->dev);
- pm_runtime_put_autosuspend(d40c->base->dev);
+
+ pm_runtime_mark_last_busy(d40c->base->dev);
+ pm_runtime_put_autosuspend(d40c->base->dev);
+ }
d40_desc_remove(d40d);
d40_desc_done(d40c, d40d);
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index ce19340..33f59ec 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -1273,11 +1273,6 @@ static int tegra_dma_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tdma);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "No mem resource for DMA\n");
- return -EINVAL;
- }
-
tdma->base_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(tdma->base_addr))
return PTR_ERR(tdma->base_addr);
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c
index 8c171fa..845f047 100644
--- a/drivers/edac/amd64_edac_inj.c
+++ b/drivers/edac/amd64_edac_inj.c
@@ -202,9 +202,9 @@ static DEVICE_ATTR(inject_word, S_IRUGO | S_IWUSR,
amd64_inject_word_show, amd64_inject_word_store);
static DEVICE_ATTR(inject_ecc_vector, S_IRUGO | S_IWUSR,
amd64_inject_ecc_vector_show, amd64_inject_ecc_vector_store);
-static DEVICE_ATTR(inject_write, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(inject_write, S_IWUSR,
NULL, amd64_inject_write_store);
-static DEVICE_ATTR(inject_read, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(inject_read, S_IWUSR,
NULL, amd64_inject_read_store);
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index b623c59..8bd1bb6 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -523,13 +523,11 @@ static void efivar_update_sysfs_entries(struct work_struct *work)
struct efivar_entry *entry;
int err;
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return;
-
/* Add new sysfs entries */
while (1) {
- memset(entry, 0, sizeof(*entry));
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return;
err = efivar_init(efivar_update_sysfs_entry, entry,
true, false, &efivar_sysfs_list);
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 87d5670..573c449 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -636,7 +636,7 @@ config GPIO_MAX7301
config GPIO_MCP23S08
tristate "Microchip MCP23xxx I/O expander"
- depends on SPI_MASTER || I2C
+ depends on (SPI_MASTER && !I2C) || I2C
help
SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017
I/O expanders.
diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c
index 634c3d3..62ef10a 100644
--- a/drivers/gpio/gpio-langwell.c
+++ b/drivers/gpio/gpio-langwell.c
@@ -324,6 +324,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
resource_size_t start, len;
struct lnw_gpio *lnw;
u32 gpio_base;
+ u32 irq_base;
int retval;
int ngpio = id->driver_data;
@@ -345,6 +346,7 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
retval = -EFAULT;
goto err_ioremap;
}
+ irq_base = *(u32 *)base;
gpio_base = *((u32 *)base + 1);
/* release the IO mapping, since we already get the info from bar1 */
iounmap(base);
@@ -365,13 +367,6 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
goto err_ioremap;
}
- lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
- &lnw_gpio_irq_ops, lnw);
- if (!lnw->domain) {
- retval = -ENOMEM;
- goto err_ioremap;
- }
-
lnw->reg_base = base;
lnw->chip.label = dev_name(&pdev->dev);
lnw->chip.request = lnw_gpio_request;
@@ -384,6 +379,14 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
lnw->chip.ngpio = ngpio;
lnw->chip.can_sleep = 0;
lnw->pdev = pdev;
+
+ lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base,
+ &lnw_gpio_irq_ops, lnw);
+ if (!lnw->domain) {
+ retval = -ENOMEM;
+ goto err_ioremap;
+ }
+
pci_set_drvdata(pdev, lnw);
retval = gpiochip_add(&lnw->chip);
if (retval) {
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index b733665..0966f26 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -496,8 +496,7 @@ err_irq_alloc_descs:
err_gpiochip_add:
while (--i >= 0) {
chip--;
- ret = gpiochip_remove(&chip->gpio);
- if (ret)
+ if (gpiochip_remove(&chip->gpio))
dev_err(&pdev->dev, "Failed gpiochip_remove(%d)\n", i);
}
kfree(chip_save);
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index bf69a7e..3a4816a 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -619,11 +619,6 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
* per-CPU registers */
if (soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- dev_err(&pdev->dev, "Cannot get memory resource\n");
- return -ENODEV;
- }
-
mvchip->percpu_membase = devm_ioremap_resource(&pdev->dev,
res);
if (IS_ERR(mvchip->percpu_membase))
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index 25000b0..f8e6af2 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -326,7 +326,8 @@ static int mxs_gpio_probe(struct platform_device *pdev)
err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + PINCTRL_DIN(port),
- port->base + PINCTRL_DOUT(port), NULL,
+ port->base + PINCTRL_DOUT(port) + MXS_SET,
+ port->base + PINCTRL_DOUT(port) + MXS_CLR,
port->base + PINCTRL_DOE(port), NULL, 0);
if (err)
goto out_irqdesc_free;
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 2050891..d3f7d2d 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -69,6 +69,7 @@ struct gpio_bank {
bool is_mpuio;
bool dbck_flag;
bool loses_context;
+ bool context_valid;
int stride;
u32 width;
int context_loss_count;
@@ -1128,6 +1129,10 @@ static int omap_gpio_probe(struct platform_device *pdev)
bank->loses_context = true;
} else {
bank->loses_context = pdata->loses_context;
+
+ if (bank->loses_context)
+ bank->get_context_loss_count =
+ pdata->get_context_loss_count;
}
@@ -1178,9 +1183,6 @@ static int omap_gpio_probe(struct platform_device *pdev)
omap_gpio_chip_init(bank);
omap_gpio_show_rev(bank);
- if (bank->loses_context)
- bank->get_context_loss_count = pdata->get_context_loss_count;
-
pm_runtime_put(bank->dev);
list_add_tail(&bank->node, &omap_gpio_list);
@@ -1259,6 +1261,8 @@ update_gpio_context_count:
return 0;
}
+static void omap_gpio_init_context(struct gpio_bank *p);
+
static int omap_gpio_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1268,6 +1272,20 @@ static int omap_gpio_runtime_resume(struct device *dev)
int c;
spin_lock_irqsave(&bank->lock, flags);
+
+ /*
+ * On the first resume during the probe, the context has not
+ * been initialised and so initialise it now. Also initialise
+ * the context loss count.
+ */
+ if (bank->loses_context && !bank->context_valid) {
+ omap_gpio_init_context(bank);
+
+ if (bank->get_context_loss_count)
+ bank->context_loss_count =
+ bank->get_context_loss_count(bank->dev);
+ }
+
_gpio_dbck_enable(bank);
/*
@@ -1384,6 +1402,29 @@ void omap2_gpio_resume_after_idle(void)
}
#if defined(CONFIG_PM_RUNTIME)
+static void omap_gpio_init_context(struct gpio_bank *p)
+{
+ struct omap_gpio_reg_offs *regs = p->regs;
+ void __iomem *base = p->base;
+
+ p->context.ctrl = __raw_readl(base + regs->ctrl);
+ p->context.oe = __raw_readl(base + regs->direction);
+ p->context.wake_en = __raw_readl(base + regs->wkup_en);
+ p->context.leveldetect0 = __raw_readl(base + regs->leveldetect0);
+ p->context.leveldetect1 = __raw_readl(base + regs->leveldetect1);
+ p->context.risingdetect = __raw_readl(base + regs->risingdetect);
+ p->context.fallingdetect = __raw_readl(base + regs->fallingdetect);
+ p->context.irqenable1 = __raw_readl(base + regs->irqenable);
+ p->context.irqenable2 = __raw_readl(base + regs->irqenable2);
+
+ if (regs->set_dataout && p->regs->clr_dataout)
+ p->context.dataout = __raw_readl(base + regs->set_dataout);
+ else
+ p->context.dataout = __raw_readl(base + regs->dataout);
+
+ p->context_valid = true;
+}
+
static void omap_gpio_restore_context(struct gpio_bank *bank)
{
__raw_writel(bank->context.wake_en,
@@ -1421,6 +1462,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
#else
#define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL
+static void omap_gpio_init_context(struct gpio_bank *p) {}
#endif
static const struct dev_pm_ops gpio_pm_ops = {
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index cdf5996..0fec097 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -424,8 +424,7 @@ end:
err_request_irq:
irq_free_descs(irq_base, gpio_pins[chip->ioh]);
- ret = gpiochip_remove(&chip->gpio);
- if (ret)
+ if (gpiochip_remove(&chip->gpio))
dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
err_gpiochip_add:
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 1e4de16..5af6571 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -272,10 +272,8 @@ static int sch_gpio_probe(struct platform_device *pdev)
return 0;
err_sch_gpio_resume:
- err = gpiochip_remove(&sch_gpio_core);
- if (err)
- dev_err(&pdev->dev, "%s failed, %d\n",
- "gpiochip_remove()", err);
+ if (gpiochip_remove(&sch_gpio_core))
+ dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
err_sch_gpio_core:
release_region(res->start, resource_size(res));
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index da4cb5b..9a62672 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -463,11 +463,6 @@ static int tegra_gpio_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Missing MEM resource\n");
- return -ENODEV;
- }
-
regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(regs))
return PTR_ERR(regs);
diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c
index 095ab14..5ac2919 100644
--- a/drivers/gpio/gpio-viperboard.c
+++ b/drivers/gpio/gpio-viperboard.c
@@ -446,7 +446,8 @@ static int vprbrd_gpio_probe(struct platform_device *pdev)
return ret;
err_gpiob:
- ret = gpiochip_remove(&vb_gpio->gpioa);
+ if (gpiochip_remove(&vb_gpio->gpioa))
+ dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
err_gpioa:
return ret;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 3a8f7e6d..e7e9242 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -78,6 +78,10 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
{
struct drm_crtc *crtc;
+ /* Locking is currently fubar in the panic handler. */
+ if (oops_in_progress)
+ return;
+
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
WARN_ON(!mutex_is_locked(&crtc->mutex));
@@ -246,6 +250,7 @@ char *drm_get_connector_status_name(enum drm_connector_status status)
else
return "unknown";
}
+EXPORT_SYMBOL(drm_get_connector_status_name);
/**
* drm_mode_object_get - allocate a new modeset identifier
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index e974f93..ed1334e 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -121,6 +121,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
connector->helper_private;
int count = 0;
int mode_flags = 0;
+ bool verbose_prune = true;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
drm_get_connector_name(connector));
@@ -149,6 +150,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",
connector->base.id, drm_get_connector_name(connector));
drm_mode_connector_update_edid_property(connector, NULL);
+ verbose_prune = false;
goto prune;
}
@@ -182,7 +184,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
}
prune:
- drm_mode_prune_invalid(dev, &connector->modes, true);
+ drm_mode_prune_invalid(dev, &connector->modes, verbose_prune);
if (list_empty(&connector->modes))
return 0;
@@ -1005,12 +1007,20 @@ static void output_poll_execute(struct work_struct *work)
continue;
connector->status = connector->funcs->detect(connector, false);
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
- connector->base.id,
- drm_get_connector_name(connector),
- old_status, connector->status);
- if (old_status != connector->status)
+ if (old_status != connector->status) {
+ const char *old, *new;
+
+ old = drm_get_connector_status_name(old_status);
+ new = drm_get_connector_status_name(connector->status);
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] "
+ "status updated from %s to %s\n",
+ connector->base.id,
+ drm_get_connector_name(connector),
+ old, new);
+
changed = true;
+ }
}
mutex_unlock(&dev->mode_config.mutex);
@@ -1083,10 +1093,11 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
old_status = connector->status;
connector->status = connector->funcs->detect(connector, false);
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
connector->base.id,
drm_get_connector_name(connector),
- old_status, connector->status);
+ drm_get_connector_status_name(old_status),
+ drm_get_connector_status_name(connector->status));
if (old_status != connector->status)
changed = true;
}
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 8d4f2907..9cc247f 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -57,7 +57,7 @@ static int drm_version(struct drm_device *dev, void *data,
struct drm_file *file_priv);
#define DRM_IOCTL_DEF(ioctl, _func, _flags) \
- [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0}
+ [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
/** Ioctl table */
static const struct drm_ioctl_desc drm_ioctls[] = {
@@ -375,7 +375,7 @@ long drm_ioctl(struct file *filp,
{
struct drm_file *file_priv = filp->private_data;
struct drm_device *dev;
- const struct drm_ioctl_desc *ioctl;
+ const struct drm_ioctl_desc *ioctl = NULL;
drm_ioctl_t *func;
unsigned int nr = DRM_IOCTL_NR(cmd);
int retcode = -EINVAL;
@@ -392,11 +392,6 @@ long drm_ioctl(struct file *filp,
atomic_inc(&dev->counts[_DRM_STAT_IOCTLS]);
++file_priv->ioctl_count;
- DRM_DEBUG("pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n",
- task_pid_nr(current), cmd, nr,
- (long)old_encode_dev(file_priv->minor->device),
- file_priv->authenticated);
-
if ((nr >= DRM_CORE_IOCTL_COUNT) &&
((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
goto err_i1;
@@ -417,6 +412,11 @@ long drm_ioctl(struct file *filp,
} else
goto err_i1;
+ DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
+ task_pid_nr(current),
+ (long)old_encode_dev(file_priv->minor->device),
+ file_priv->authenticated, ioctl->name);
+
/* Do not trust userspace, use our own definition */
func = ioctl->func;
/* is there a local override? */
@@ -471,6 +471,12 @@ long drm_ioctl(struct file *filp,
}
err_i1:
+ if (!ioctl)
+ DRM_DEBUG("invalid iotcl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
+ task_pid_nr(current),
+ (long)old_encode_dev(file_priv->minor->device),
+ file_priv->authenticated, cmd, nr);
+
if (kdata != stack_kdata)
kfree(kdata);
atomic_dec(&dev->ioctl_count);
diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c
index 48c52f7..0cfb60f 100644
--- a/drivers/gpu/drm/drm_encoder_slave.c
+++ b/drivers/gpu/drm/drm_encoder_slave.c
@@ -54,16 +54,12 @@ int drm_i2c_encoder_init(struct drm_device *dev,
struct i2c_adapter *adap,
const struct i2c_board_info *info)
{
- char modalias[sizeof(I2C_MODULE_PREFIX)
- + I2C_NAME_SIZE];
struct module *module = NULL;
struct i2c_client *client;
struct drm_i2c_encoder_driver *encoder_drv;
int err = 0;
- snprintf(modalias, sizeof(modalias),
- "%s%s", I2C_MODULE_PREFIX, info->type);
- request_module(modalias);
+ request_module("%s%s", I2C_MODULE_PREFIX, info->type);
client = i2c_new_device(adap, info);
if (!client) {
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index a6a8643..8bcce78 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -1054,7 +1054,7 @@ EXPORT_SYMBOL(drm_vblank_off);
*/
void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
{
- /* vblank is not initialized (IRQ not installed ?) */
+ /* vblank is not initialized (IRQ not installed ?), or has been freed */
if (!dev->num_crtcs)
return;
/*
@@ -1076,6 +1076,10 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
{
unsigned long irqflags;
+ /* vblank is not initialized (IRQ not installed ?), or has been freed */
+ if (!dev->num_crtcs)
+ return;
+
if (dev->vblank_inmodeset[crtc]) {
spin_lock_irqsave(&dev->vbl_lock, irqflags);
dev->vblank_disable_allowed = 1;
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index db1e2d6..07cf99c 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -755,33 +755,35 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
EXPORT_SYMBOL(drm_mm_debug_table);
#if defined(CONFIG_DEBUG_FS)
-int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
+static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *entry)
{
- struct drm_mm_node *entry;
- unsigned long total_used = 0, total_free = 0, total = 0;
unsigned long hole_start, hole_end, hole_size;
- hole_start = drm_mm_hole_node_start(&mm->head_node);
- hole_end = drm_mm_hole_node_end(&mm->head_node);
- hole_size = hole_end - hole_start;
- if (hole_size)
+ if (entry->hole_follows) {
+ hole_start = drm_mm_hole_node_start(entry);
+ hole_end = drm_mm_hole_node_end(entry);
+ hole_size = hole_end - hole_start;
seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
hole_start, hole_end, hole_size);
- total_free += hole_size;
+ return hole_size;
+ }
+
+ return 0;
+}
+
+int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
+{
+ struct drm_mm_node *entry;
+ unsigned long total_used = 0, total_free = 0, total = 0;
+
+ total_free += drm_mm_dump_hole(m, &mm->head_node);
drm_mm_for_each_node(entry, mm) {
seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: used\n",
entry->start, entry->start + entry->size,
entry->size);
total_used += entry->size;
- if (entry->hole_follows) {
- hole_start = drm_mm_hole_node_start(entry);
- hole_end = drm_mm_hole_node_end(entry);
- hole_size = hole_end - hole_start;
- seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n",
- hole_start, hole_end, hole_size);
- total_free += hole_size;
- }
+ total_free += drm_mm_dump_hole(m, entry);
}
total = total_free + total_used;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index faa79df..a371ff8 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1143,6 +1143,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
was_digit = false;
} else
goto done;
+ break;
case '0' ... '9':
was_digit = true;
break;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index e8894bc..c200e4d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -48,6 +48,8 @@ struct exynos_drm_crtc {
unsigned int pipe;
unsigned int dpms;
enum exynos_crtc_mode mode;
+ wait_queue_head_t pending_flip_queue;
+ atomic_t pending_flip;
};
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -61,6 +63,13 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
return;
}
+ if (mode > DRM_MODE_DPMS_ON) {
+ /* wait for the completion of page flip. */
+ wait_event(exynos_crtc->pending_flip_queue,
+ atomic_read(&exynos_crtc->pending_flip) == 0);
+ drm_vblank_off(crtc->dev, exynos_crtc->pipe);
+ }
+
exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms);
exynos_crtc->dpms = mode;
}
@@ -217,7 +226,6 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
ret = drm_vblank_get(dev, exynos_crtc->pipe);
if (ret) {
DRM_DEBUG("failed to acquire vblank counter\n");
- list_del(&event->base.link);
goto out;
}
@@ -225,6 +233,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
spin_lock_irq(&dev->event_lock);
list_add_tail(&event->base.link,
&dev_priv->pageflip_event_list);
+ atomic_set(&exynos_crtc->pending_flip, 1);
spin_unlock_irq(&dev->event_lock);
crtc->fb = fb;
@@ -344,6 +353,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
exynos_crtc->pipe = nr;
exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
+ init_waitqueue_head(&exynos_crtc->pending_flip_queue);
+ atomic_set(&exynos_crtc->pending_flip, 0);
exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
if (!exynos_crtc->plane) {
kfree(exynos_crtc);
@@ -398,7 +409,8 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
{
struct exynos_drm_private *dev_priv = dev->dev_private;
struct drm_pending_vblank_event *e, *t;
- struct timeval now;
+ struct drm_crtc *drm_crtc = dev_priv->crtc[crtc];
+ struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
unsigned long flags;
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -411,14 +423,11 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
if (crtc != e->pipe)
continue;
- do_gettimeofday(&now);
- e->event.sequence = 0;
- e->event.tv_sec = now.tv_sec;
- e->event.tv_usec = now.tv_usec;
-
- list_move_tail(&e->base.link, &e->base.file_priv->event_list);
- wake_up_interruptible(&e->base.file_priv->event_wait);
+ list_del(&e->base.link);
+ drm_send_vblank_event(dev, -1, e);
drm_vblank_put(dev, crtc);
+ atomic_set(&exynos_crtc->pending_flip, 0);
+ wake_up(&exynos_crtc->pending_flip_queue);
}
spin_unlock_irqrestore(&dev->event_lock, flags);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 68f0045..8f007aa 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -182,7 +182,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd,
&exynos_gem_obj->base);
- if (IS_ERR_OR_NULL(helper->fb)) {
+ if (IS_ERR(helper->fb)) {
DRM_ERROR("failed to create drm framebuffer.\n");
ret = PTR_ERR(helper->fb);
goto err_destroy_gem;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 773f583..4a1616a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -12,9 +12,9 @@
*
*/
#include <linux/kernel.h>
-#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
@@ -1845,7 +1845,7 @@ static int fimc_probe(struct platform_device *pdev)
}
ctx->irq = res->start;
- ret = request_threaded_irq(ctx->irq, NULL, fimc_irq_handler,
+ ret = devm_request_threaded_irq(dev, ctx->irq, NULL, fimc_irq_handler,
IRQF_ONESHOT, "drm_fimc", ctx);
if (ret < 0) {
dev_err(dev, "failed to request irq.\n");
@@ -1854,7 +1854,7 @@ static int fimc_probe(struct platform_device *pdev)
ret = fimc_setup_clocks(ctx);
if (ret < 0)
- goto err_free_irq;
+ return ret;
ippdrv = &ctx->ippdrv;
ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops;
@@ -1884,7 +1884,7 @@ static int fimc_probe(struct platform_device *pdev)
goto err_pm_dis;
}
- dev_info(&pdev->dev, "drm fimc registered successfully.\n");
+ dev_info(dev, "drm fimc registered successfully.\n");
return 0;
@@ -1892,8 +1892,6 @@ err_pm_dis:
pm_runtime_disable(dev);
err_put_clk:
fimc_put_clocks(ctx);
-err_free_irq:
- free_irq(ctx->irq, ctx);
return ret;
}
@@ -1911,8 +1909,6 @@ static int fimc_remove(struct platform_device *pdev)
pm_runtime_set_suspended(dev);
pm_runtime_disable(dev);
- free_irq(ctx->irq, ctx);
-
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 746b282..97c61db 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -885,7 +885,7 @@ static int fimd_probe(struct platform_device *pdev)
DRM_DEBUG_KMS("%s\n", __FILE__);
- if (pdev->dev.of_node) {
+ if (dev->of_node) {
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
DRM_ERROR("memory allocation for pdata failed\n");
@@ -899,7 +899,7 @@ static int fimd_probe(struct platform_device *pdev)
return ret;
}
} else {
- pdata = pdev->dev.platform_data;
+ pdata = dev->platform_data;
if (!pdata) {
DRM_ERROR("no platform data specified\n");
return -EINVAL;
@@ -912,7 +912,7 @@ static int fimd_probe(struct platform_device *pdev)
return -EINVAL;
}
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
@@ -930,7 +930,7 @@ static int fimd_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- ctx->regs = devm_ioremap_resource(&pdev->dev, res);
+ ctx->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(ctx->regs))
return PTR_ERR(ctx->regs);
@@ -942,7 +942,7 @@ static int fimd_probe(struct platform_device *pdev)
ctx->irq = res->start;
- ret = devm_request_irq(&pdev->dev, ctx->irq, fimd_irq_handler,
+ ret = devm_request_irq(dev, ctx->irq, fimd_irq_handler,
0, "drm_fimd", ctx);
if (ret) {
dev_err(dev, "irq request failed.\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 47a493c..af75434 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -1379,7 +1379,7 @@ static int g2d_probe(struct platform_device *pdev)
struct exynos_drm_subdrv *subdrv;
int ret;
- g2d = devm_kzalloc(&pdev->dev, sizeof(*g2d), GFP_KERNEL);
+ g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL);
if (!g2d) {
dev_err(dev, "failed to allocate driver data\n");
return -ENOMEM;
@@ -1417,7 +1417,7 @@ static int g2d_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- g2d->regs = devm_ioremap_resource(&pdev->dev, res);
+ g2d->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(g2d->regs)) {
ret = PTR_ERR(g2d->regs);
goto err_put_clk;
@@ -1430,7 +1430,7 @@ static int g2d_probe(struct platform_device *pdev)
goto err_put_clk;
}
- ret = devm_request_irq(&pdev->dev, g2d->irq, g2d_irq_handler, 0,
+ ret = devm_request_irq(dev, g2d->irq, g2d_irq_handler, 0,
"drm_g2d", g2d);
if (ret < 0) {
dev_err(dev, "irq request failed\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 7841c3b..762f40d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -1704,7 +1704,7 @@ static int gsc_probe(struct platform_device *pdev)
}
ctx->irq = res->start;
- ret = request_threaded_irq(ctx->irq, NULL, gsc_irq_handler,
+ ret = devm_request_threaded_irq(dev, ctx->irq, NULL, gsc_irq_handler,
IRQF_ONESHOT, "drm_gsc", ctx);
if (ret < 0) {
dev_err(dev, "failed to request irq.\n");
@@ -1725,7 +1725,7 @@ static int gsc_probe(struct platform_device *pdev)
ret = gsc_init_prop_list(ippdrv);
if (ret < 0) {
dev_err(dev, "failed to init property list.\n");
- goto err_get_irq;
+ return ret;
}
DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
@@ -1743,15 +1743,12 @@ static int gsc_probe(struct platform_device *pdev)
goto err_ippdrv_register;
}
- dev_info(&pdev->dev, "drm gsc registered successfully.\n");
+ dev_info(dev, "drm gsc registered successfully.\n");
return 0;
err_ippdrv_register:
- devm_kfree(dev, ippdrv->prop_list);
pm_runtime_disable(dev);
-err_get_irq:
- free_irq(ctx->irq, ctx);
return ret;
}
@@ -1761,15 +1758,12 @@ static int gsc_remove(struct platform_device *pdev)
struct gsc_context *ctx = get_gsc_context(dev);
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
- devm_kfree(dev, ippdrv->prop_list);
exynos_drm_ippdrv_unregister(ippdrv);
mutex_destroy(&ctx->lock);
pm_runtime_set_suspended(dev);
pm_runtime_disable(dev);
- free_irq(ctx->irq, ctx);
-
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index ba2f0f1..437fb94 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -442,7 +442,7 @@ static int exynos_drm_hdmi_probe(struct platform_device *pdev)
DRM_DEBUG_KMS("%s\n", __FILE__);
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
DRM_LOG_KMS("failed to alloc common hdmi context.\n");
return -ENOMEM;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index 29d2ad3..be1e884 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -222,7 +222,7 @@ static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx,
/* find ipp driver using idr */
ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock,
ipp_id);
- if (IS_ERR_OR_NULL(ippdrv)) {
+ if (IS_ERR(ippdrv)) {
DRM_ERROR("not found ipp%d driver.\n", ipp_id);
return ippdrv;
}
@@ -388,7 +388,7 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property)
DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, prop_id);
ippdrv = ipp_find_drv_by_handle(prop_id);
- if (IS_ERR_OR_NULL(ippdrv)) {
+ if (IS_ERR(ippdrv)) {
DRM_ERROR("failed to get ipp driver.\n");
return -EINVAL;
}
@@ -492,7 +492,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
/* find ipp driver using ipp id */
ippdrv = ipp_find_driver(ctx, property);
- if (IS_ERR_OR_NULL(ippdrv)) {
+ if (IS_ERR(ippdrv)) {
DRM_ERROR("failed to get ipp driver.\n");
return -EINVAL;
}
@@ -521,19 +521,19 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
c_node->state = IPP_STATE_IDLE;
c_node->start_work = ipp_create_cmd_work();
- if (IS_ERR_OR_NULL(c_node->start_work)) {
+ if (IS_ERR(c_node->start_work)) {
DRM_ERROR("failed to create start work.\n");
goto err_clear;
}
c_node->stop_work = ipp_create_cmd_work();
- if (IS_ERR_OR_NULL(c_node->stop_work)) {
+ if (IS_ERR(c_node->stop_work)) {
DRM_ERROR("failed to create stop work.\n");
goto err_free_start;
}
c_node->event_work = ipp_create_event_work();
- if (IS_ERR_OR_NULL(c_node->event_work)) {
+ if (IS_ERR(c_node->event_work)) {
DRM_ERROR("failed to create event work.\n");
goto err_free_stop;
}
@@ -915,7 +915,7 @@ static int ipp_queue_buf_with_run(struct device *dev,
DRM_DEBUG_KMS("%s\n", __func__);
ippdrv = ipp_find_drv_by_handle(qbuf->prop_id);
- if (IS_ERR_OR_NULL(ippdrv)) {
+ if (IS_ERR(ippdrv)) {
DRM_ERROR("failed to get ipp driver.\n");
return -EFAULT;
}
@@ -1909,7 +1909,7 @@ static int ipp_probe(struct platform_device *pdev)
struct exynos_drm_subdrv *subdrv;
int ret;
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
@@ -1963,7 +1963,7 @@ static int ipp_probe(struct platform_device *pdev)
goto err_cmd_workq;
}
- dev_info(&pdev->dev, "drm ipp registered successfully.\n");
+ dev_info(dev, "drm ipp registered successfully.\n");
return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index 947f09f..9b6c709 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -666,8 +666,8 @@ static int rotator_probe(struct platform_device *pdev)
return rot->irq;
}
- ret = request_threaded_irq(rot->irq, NULL, rotator_irq_handler,
- IRQF_ONESHOT, "drm_rotator", rot);
+ ret = devm_request_threaded_irq(dev, rot->irq, NULL,
+ rotator_irq_handler, IRQF_ONESHOT, "drm_rotator", rot);
if (ret < 0) {
dev_err(dev, "failed to request irq\n");
return ret;
@@ -676,8 +676,7 @@ static int rotator_probe(struct platform_device *pdev)
rot->clock = devm_clk_get(dev, "rotator");
if (IS_ERR(rot->clock)) {
dev_err(dev, "failed to get clock\n");
- ret = PTR_ERR(rot->clock);
- goto err_clk_get;
+ return PTR_ERR(rot->clock);
}
pm_runtime_enable(dev);
@@ -709,10 +708,7 @@ static int rotator_probe(struct platform_device *pdev)
return 0;
err_ippdrv_register:
- devm_kfree(dev, ippdrv->prop_list);
pm_runtime_disable(dev);
-err_clk_get:
- free_irq(rot->irq, rot);
return ret;
}
@@ -722,13 +718,10 @@ static int rotator_remove(struct platform_device *pdev)
struct rot_context *rot = dev_get_drvdata(dev);
struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;
- devm_kfree(dev, ippdrv->prop_list);
exynos_drm_ippdrv_unregister(ippdrv);
pm_runtime_disable(dev);
- free_irq(rot->irq, rot);
-
return 0;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 9504b0c..24376c1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -594,7 +594,7 @@ static int vidi_probe(struct platform_device *pdev)
DRM_DEBUG_KMS("%s\n", __FILE__);
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
@@ -612,7 +612,7 @@ static int vidi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
- ret = device_create_file(&pdev->dev, &dev_attr_connection);
+ ret = device_create_file(dev, &dev_attr_connection);
if (ret < 0)
DRM_INFO("failed to create connection sysfs.\n");
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index bbfc384..fd1426d 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1946,14 +1946,14 @@ static int hdmi_probe(struct platform_device *pdev)
DRM_DEBUG_KMS("[%d]\n", __LINE__);
- if (pdev->dev.of_node) {
+ if (dev->of_node) {
pdata = drm_hdmi_dt_parse_pdata(dev);
if (IS_ERR(pdata)) {
DRM_ERROR("failed to parse dt\n");
return PTR_ERR(pdata);
}
} else {
- pdata = pdev->dev.platform_data;
+ pdata = dev->platform_data;
}
if (!pdata) {
@@ -1961,14 +1961,14 @@ static int hdmi_probe(struct platform_device *pdev)
return -EINVAL;
}
- drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
+ drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
GFP_KERNEL);
if (!drm_hdmi_ctx) {
DRM_ERROR("failed to allocate common hdmi context.\n");
return -ENOMEM;
}
- hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_context),
+ hdata = devm_kzalloc(dev, sizeof(struct hdmi_context),
GFP_KERNEL);
if (!hdata) {
DRM_ERROR("out of memory\n");
@@ -1985,7 +1985,7 @@ static int hdmi_probe(struct platform_device *pdev)
if (dev->of_node) {
const struct of_device_id *match;
match = of_match_node(of_match_ptr(hdmi_match_types),
- pdev->dev.of_node);
+ dev->of_node);
if (match == NULL)
return -ENODEV;
hdata->type = (enum hdmi_type)match->data;
@@ -2005,16 +2005,11 @@ static int hdmi_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- DRM_ERROR("failed to find registers\n");
- return -ENOENT;
- }
-
- hdata->regs = devm_ioremap_resource(&pdev->dev, res);
+ hdata->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(hdata->regs))
return PTR_ERR(hdata->regs);
- ret = devm_gpio_request(&pdev->dev, hdata->hpd_gpio, "HPD");
+ ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
if (ret) {
DRM_ERROR("failed to request HPD gpio\n");
return ret;
@@ -2046,7 +2041,7 @@ static int hdmi_probe(struct platform_device *pdev)
hdata->hpd = gpio_get_value(hdata->hpd_gpio);
- ret = request_threaded_irq(hdata->irq, NULL,
+ ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
hdmi_irq_thread, IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"hdmi", drm_hdmi_ctx);
@@ -2075,16 +2070,11 @@ err_ddc:
static int hdmi_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
- struct hdmi_context *hdata = ctx->ctx;
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
pm_runtime_disable(dev);
- free_irq(hdata->irq, hdata);
-
-
/* hdmiphy i2c driver */
i2c_del_driver(&hdmiphy_driver);
/* DDC i2c driver */
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index ec3e376..7c197d38 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -1061,7 +1061,7 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
return -ENXIO;
}
- mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
+ mixer_res->mixer_regs = devm_ioremap(dev, res->start,
resource_size(res));
if (mixer_res->mixer_regs == NULL) {
dev_err(dev, "register mapping failed.\n");
@@ -1074,7 +1074,7 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
return -ENXIO;
}
- ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler,
+ ret = devm_request_irq(dev, res->start, mixer_irq_handler,
0, "drm_mixer", ctx);
if (ret) {
dev_err(dev, "request interrupt failed.\n");
@@ -1118,7 +1118,7 @@ static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
return -ENXIO;
}
- mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start,
+ mixer_res->vp_regs = devm_ioremap(dev, res->start,
resource_size(res));
if (mixer_res->vp_regs == NULL) {
dev_err(dev, "register mapping failed.\n");
@@ -1169,14 +1169,14 @@ static int mixer_probe(struct platform_device *pdev)
dev_info(dev, "probe start\n");
- drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
+ drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
GFP_KERNEL);
if (!drm_hdmi_ctx) {
DRM_ERROR("failed to allocate common hdmi context.\n");
return -ENOMEM;
}
- ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
DRM_ERROR("failed to alloc mixer context.\n");
return -ENOMEM;
@@ -1187,14 +1187,14 @@ static int mixer_probe(struct platform_device *pdev)
if (dev->of_node) {
const struct of_device_id *match;
match = of_match_node(of_match_ptr(mixer_match_types),
- pdev->dev.of_node);
+ dev->of_node);
drv = (struct mixer_drv_data *)match->data;
} else {
drv = (struct mixer_drv_data *)
platform_get_device_id(pdev)->driver_data;
}
- ctx->dev = &pdev->dev;
+ ctx->dev = dev;
ctx->parent_ctx = (void *)drm_hdmi_ctx;
drm_hdmi_ctx->ctx = (void *)ctx;
ctx->vp_enabled = drv->is_vp_enabled;
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index 3cfd093..82430ad 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -1462,7 +1462,7 @@ static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc,
size_t addr = 0;
struct gtt_range *gt;
struct drm_gem_object *obj;
- int ret;
+ int ret = 0;
/* if we want to turn of the cursor ignore width and height */
if (!handle) {
@@ -1499,7 +1499,8 @@ static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc,
if (obj->size < width * height * 4) {
dev_dbg(dev->dev, "buffer is to small\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unref_cursor;
}
gt = container_of(obj, struct gtt_range, gem);
@@ -1508,7 +1509,7 @@ static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc,
ret = psb_gtt_pin(gt);
if (ret) {
dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle);
- return ret;
+ goto unref_cursor;
}
addr = gt->offset; /* Or resource.start ??? */
@@ -1532,9 +1533,14 @@ static int cdv_intel_crtc_cursor_set(struct drm_crtc *crtc,
struct gtt_range, gem);
psb_gtt_unpin(gt);
drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
- psb_intel_crtc->cursor_obj = obj;
}
- return 0;
+
+ psb_intel_crtc->cursor_obj = obj;
+ return ret;
+
+unref_cursor:
+ drm_gem_object_unreference(obj);
+ return ret;
}
static int cdv_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
@@ -1750,6 +1756,19 @@ static void cdv_intel_crtc_destroy(struct drm_crtc *crtc)
kfree(psb_intel_crtc);
}
+static void cdv_intel_crtc_disable(struct drm_crtc *crtc)
+{
+ struct gtt_range *gt;
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+
+ if (crtc->fb) {
+ gt = to_psb_fb(crtc->fb)->gtt;
+ psb_gtt_unpin(gt);
+ }
+}
+
const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = {
.dpms = cdv_intel_crtc_dpms,
.mode_fixup = cdv_intel_crtc_mode_fixup,
@@ -1757,6 +1776,7 @@ const struct drm_crtc_helper_funcs cdv_intel_helper_funcs = {
.mode_set_base = cdv_intel_pipe_set_base,
.prepare = cdv_intel_crtc_prepare,
.commit = cdv_intel_crtc_commit,
+ .disable = cdv_intel_crtc_disable,
};
const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 1534e22..8b1b6d9 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -121,8 +121,8 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
unsigned long address;
int ret;
unsigned long pfn;
- /* FIXME: assumes fb at stolen base which may not be true */
- unsigned long phys_addr = (unsigned long)dev_priv->stolen_base;
+ unsigned long phys_addr = (unsigned long)dev_priv->stolen_base +
+ psbfb->gtt->offset;
page_num = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
address = (unsigned long)vmf->virtual_address - (vmf->pgoff << PAGE_SHIFT);
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 6e8f42b..6666493 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -843,7 +843,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
struct gtt_range *cursor_gt = psb_intel_crtc->cursor_gt;
struct drm_gem_object *obj;
void *tmp_dst, *tmp_src;
- int ret, i, cursor_pages;
+ int ret = 0, i, cursor_pages;
/* if we want to turn of the cursor ignore width and height */
if (!handle) {
@@ -880,7 +880,8 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
if (obj->size < width * height * 4) {
dev_dbg(dev->dev, "buffer is to small\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unref_cursor;
}
gt = container_of(obj, struct gtt_range, gem);
@@ -889,13 +890,14 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
ret = psb_gtt_pin(gt);
if (ret) {
dev_err(dev->dev, "Can not pin down handle 0x%x\n", handle);
- return ret;
+ goto unref_cursor;
}
if (dev_priv->ops->cursor_needs_phys) {
if (cursor_gt == NULL) {
dev_err(dev->dev, "No hardware cursor mem available");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto unref_cursor;
}
/* Prevent overflow */
@@ -936,9 +938,14 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
struct gtt_range, gem);
psb_gtt_unpin(gt);
drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
- psb_intel_crtc->cursor_obj = obj;
}
- return 0;
+
+ psb_intel_crtc->cursor_obj = obj;
+ return ret;
+
+unref_cursor:
+ drm_gem_object_unreference(obj);
+ return ret;
}
static int psb_intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
@@ -1150,6 +1157,19 @@ static void psb_intel_crtc_destroy(struct drm_crtc *crtc)
kfree(psb_intel_crtc);
}
+static void psb_intel_crtc_disable(struct drm_crtc *crtc)
+{
+ struct gtt_range *gt;
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+
+ if (crtc->fb) {
+ gt = to_psb_fb(crtc->fb)->gtt;
+ psb_gtt_unpin(gt);
+ }
+}
+
const struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
.dpms = psb_intel_crtc_dpms,
.mode_fixup = psb_intel_crtc_mode_fixup,
@@ -1157,6 +1177,7 @@ const struct drm_crtc_helper_funcs psb_intel_helper_funcs = {
.mode_set_base = psb_intel_pipe_set_base,
.prepare = psb_intel_crtc_prepare,
.commit = psb_intel_crtc_commit,
+ .disable = psb_intel_crtc_disable,
};
const struct drm_crtc_funcs psb_intel_crtc_funcs = {
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 9ebe895..a2e4953 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -364,40 +364,64 @@ static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */
INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */
- INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT2 desktop */
+ INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT3 desktop */
INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */
INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */
- INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT2 server */
+ INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT3 server */
INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */
INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */
INTEL_VGA_DEVICE(0x0426, &intel_haswell_m_info), /* GT2 mobile */
+ INTEL_VGA_DEVICE(0x040B, &intel_haswell_d_info), /* GT1 reserved */
+ INTEL_VGA_DEVICE(0x041B, &intel_haswell_d_info), /* GT2 reserved */
+ INTEL_VGA_DEVICE(0x042B, &intel_haswell_d_info), /* GT3 reserved */
+ INTEL_VGA_DEVICE(0x040E, &intel_haswell_d_info), /* GT1 reserved */
+ INTEL_VGA_DEVICE(0x041E, &intel_haswell_d_info), /* GT2 reserved */
+ INTEL_VGA_DEVICE(0x042E, &intel_haswell_d_info), /* GT3 reserved */
INTEL_VGA_DEVICE(0x0C02, &intel_haswell_d_info), /* SDV GT1 desktop */
INTEL_VGA_DEVICE(0x0C12, &intel_haswell_d_info), /* SDV GT2 desktop */
- INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT2 desktop */
+ INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT3 desktop */
INTEL_VGA_DEVICE(0x0C0A, &intel_haswell_d_info), /* SDV GT1 server */
INTEL_VGA_DEVICE(0x0C1A, &intel_haswell_d_info), /* SDV GT2 server */
- INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT2 server */
+ INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT3 server */
INTEL_VGA_DEVICE(0x0C06, &intel_haswell_m_info), /* SDV GT1 mobile */
INTEL_VGA_DEVICE(0x0C16, &intel_haswell_m_info), /* SDV GT2 mobile */
- INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT2 mobile */
+ INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT3 mobile */
+ INTEL_VGA_DEVICE(0x0C0B, &intel_haswell_d_info), /* SDV GT1 reserved */
+ INTEL_VGA_DEVICE(0x0C1B, &intel_haswell_d_info), /* SDV GT2 reserved */
+ INTEL_VGA_DEVICE(0x0C2B, &intel_haswell_d_info), /* SDV GT3 reserved */
+ INTEL_VGA_DEVICE(0x0C0E, &intel_haswell_d_info), /* SDV GT1 reserved */
+ INTEL_VGA_DEVICE(0x0C1E, &intel_haswell_d_info), /* SDV GT2 reserved */
+ INTEL_VGA_DEVICE(0x0C2E, &intel_haswell_d_info), /* SDV GT3 reserved */
INTEL_VGA_DEVICE(0x0A02, &intel_haswell_d_info), /* ULT GT1 desktop */
INTEL_VGA_DEVICE(0x0A12, &intel_haswell_d_info), /* ULT GT2 desktop */
- INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT2 desktop */
+ INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT3 desktop */
INTEL_VGA_DEVICE(0x0A0A, &intel_haswell_d_info), /* ULT GT1 server */
INTEL_VGA_DEVICE(0x0A1A, &intel_haswell_d_info), /* ULT GT2 server */
- INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT2 server */
+ INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT3 server */
INTEL_VGA_DEVICE(0x0A06, &intel_haswell_m_info), /* ULT GT1 mobile */
INTEL_VGA_DEVICE(0x0A16, &intel_haswell_m_info), /* ULT GT2 mobile */
- INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT2 mobile */
+ INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT3 mobile */
+ INTEL_VGA_DEVICE(0x0A0B, &intel_haswell_d_info), /* ULT GT1 reserved */
+ INTEL_VGA_DEVICE(0x0A1B, &intel_haswell_d_info), /* ULT GT2 reserved */
+ INTEL_VGA_DEVICE(0x0A2B, &intel_haswell_d_info), /* ULT GT3 reserved */
+ INTEL_VGA_DEVICE(0x0A0E, &intel_haswell_m_info), /* ULT GT1 reserved */
+ INTEL_VGA_DEVICE(0x0A1E, &intel_haswell_m_info), /* ULT GT2 reserved */
+ INTEL_VGA_DEVICE(0x0A2E, &intel_haswell_m_info), /* ULT GT3 reserved */
INTEL_VGA_DEVICE(0x0D02, &intel_haswell_d_info), /* CRW GT1 desktop */
INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT2 desktop */
- INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT2 desktop */
+ INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT3 desktop */
INTEL_VGA_DEVICE(0x0D0A, &intel_haswell_d_info), /* CRW GT1 server */
INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT2 server */
- INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT2 server */
+ INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT3 server */
INTEL_VGA_DEVICE(0x0D06, &intel_haswell_m_info), /* CRW GT1 mobile */
INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */
- INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */
+ INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT3 mobile */
+ INTEL_VGA_DEVICE(0x0D0B, &intel_haswell_d_info), /* CRW GT1 reserved */
+ INTEL_VGA_DEVICE(0x0D1B, &intel_haswell_d_info), /* CRW GT2 reserved */
+ INTEL_VGA_DEVICE(0x0D2B, &intel_haswell_d_info), /* CRW GT3 reserved */
+ INTEL_VGA_DEVICE(0x0D0E, &intel_haswell_d_info), /* CRW GT1 reserved */
+ INTEL_VGA_DEVICE(0x0D1E, &intel_haswell_d_info), /* CRW GT2 reserved */
+ INTEL_VGA_DEVICE(0x0D2E, &intel_haswell_d_info), /* CRW GT3 reserved */
INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info),
INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info),
INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info),
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d5dcf7f..b9d00dc 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1943,4 +1943,19 @@ static inline void __user *to_user_ptr(u64 address)
return (void __user *)(uintptr_t)address;
}
+static inline unsigned long msecs_to_jiffies_timeout(const unsigned int m)
+{
+ unsigned long j = msecs_to_jiffies(m);
+
+ return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1);
+}
+
+static inline unsigned long
+timespec_to_jiffies_timeout(const struct timespec *value)
+{
+ unsigned long j = timespec_to_jiffies(value);
+
+ return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1);
+}
+
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 6be940e..970ad17 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -91,14 +91,11 @@ i915_gem_wait_for_error(struct i915_gpu_error *error)
{
int ret;
-#define EXIT_COND (!i915_reset_in_progress(error))
+#define EXIT_COND (!i915_reset_in_progress(error) || \
+ i915_terminally_wedged(error))
if (EXIT_COND)
return 0;
- /* GPU is already declared terminally dead, give up. */
- if (i915_terminally_wedged(error))
- return -EIO;
-
/*
* Only wait 10 seconds for the gpu reset to complete to avoid hanging
* userspace. If it takes that long something really bad is going on and
@@ -1003,7 +1000,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
wait_forever = false;
}
- timeout_jiffies = timespec_to_jiffies(&wait_time);
+ timeout_jiffies = timespec_to_jiffies_timeout(&wait_time);
if (WARN_ON(!ring->irq_get(ring)))
return -ENODEV;
@@ -1045,6 +1042,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
if (timeout) {
struct timespec sleep_time = timespec_sub(now, before);
*timeout = timespec_sub(*timeout, sleep_time);
+ if (!timespec_valid(timeout)) /* i.e. negative time remains */
+ set_normalized_timespec(timeout, 0, 0);
}
switch (end) {
@@ -1053,8 +1052,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
case -ERESTARTSYS: /* Signal */
return (int)end;
case 0: /* Timeout */
- if (timeout)
- set_normalized_timespec(timeout, 0, 0);
return -ETIME;
default: /* Completed */
WARN_ON(end < 0); /* We're not aware of other errors */
@@ -2377,10 +2374,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
mutex_unlock(&dev->struct_mutex);
ret = __wait_seqno(ring, seqno, reset_counter, true, timeout);
- if (timeout) {
- WARN_ON(!timespec_valid(timeout));
+ if (timeout)
args->timeout_ns = timespec_to_ns(timeout);
- }
return ret;
out:
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index dca614d..bdb0d77 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -709,15 +709,6 @@ static inline size_t gen6_get_stolen_size(u16 snb_gmch_ctl)
return snb_gmch_ctl << 25; /* 32 MB units */
}
-static inline size_t gen7_get_stolen_size(u16 snb_gmch_ctl)
-{
- static const int stolen_decoder[] = {
- 0, 0, 0, 0, 0, 32, 48, 64, 128, 256, 96, 160, 224, 352};
- snb_gmch_ctl >>= IVB_GMCH_GMS_SHIFT;
- snb_gmch_ctl &= IVB_GMCH_GMS_MASK;
- return stolen_decoder[snb_gmch_ctl] << 20;
-}
-
static int gen6_gmch_probe(struct drm_device *dev,
size_t *gtt_total,
size_t *stolen,
@@ -747,11 +738,7 @@ static int gen6_gmch_probe(struct drm_device *dev,
pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &snb_gmch_ctl);
gtt_size = gen6_get_total_gtt_size(snb_gmch_ctl);
- if (IS_GEN7(dev) && !IS_VALLEYVIEW(dev))
- *stolen = gen7_get_stolen_size(snb_gmch_ctl);
- else
- *stolen = gen6_get_stolen_size(snb_gmch_ctl);
-
+ *stolen = gen6_get_stolen_size(snb_gmch_ctl);
*gtt_total = (gtt_size / sizeof(gen6_gtt_pte_t)) << PAGE_SHIFT;
/* For Modern GENs the PTEs and register space are split in the BAR */
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 83f9c26..2d6b62e 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -46,8 +46,6 @@
#define SNB_GMCH_GGMS_MASK 0x3
#define SNB_GMCH_GMS_SHIFT 3 /* Graphics Mode Select */
#define SNB_GMCH_GMS_MASK 0x1f
-#define IVB_GMCH_GMS_SHIFT 4
-#define IVB_GMCH_GMS_MASK 0xf
/* PCI config space */
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 26a0a57..fb961bb 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1265,6 +1265,8 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
+ if (port != PORT_A)
+ intel_dp_stop_link_train(intel_dp);
}
}
@@ -1326,6 +1328,9 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
} else if (type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ if (port == PORT_A)
+ intel_dp_stop_link_train(intel_dp);
+
ironlake_edp_backlight_on(intel_dp);
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index efe8299..56746dc 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7937,6 +7937,11 @@ intel_modeset_check_state(struct drm_device *dev)
memset(&pipe_config, 0, sizeof(pipe_config));
active = dev_priv->display.get_pipe_config(crtc,
&pipe_config);
+
+ /* hw state is inconsistent with the pipe A quirk */
+ if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
+ active = crtc->active;
+
WARN(crtc->active != active,
"crtc active state doesn't match with hw state "
"(expected %i, found %i)\n", crtc->active, active);
@@ -8140,6 +8145,21 @@ static void intel_set_config_restore_state(struct drm_device *dev,
}
}
+static bool
+is_crtc_connector_off(struct drm_crtc *crtc, struct drm_connector *connectors,
+ int num_connectors)
+{
+ int i;
+
+ for (i = 0; i < num_connectors; i++)
+ if (connectors[i].encoder &&
+ connectors[i].encoder->crtc == crtc &&
+ connectors[i].dpms != DRM_MODE_DPMS_ON)
+ return true;
+
+ return false;
+}
+
static void
intel_set_config_compute_mode_changes(struct drm_mode_set *set,
struct intel_set_config *config)
@@ -8147,7 +8167,11 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
/* We should be able to check here if the fb has the same properties
* and then just flip_or_move it */
- if (set->crtc->fb != set->fb) {
+ if (set->connectors != NULL &&
+ is_crtc_connector_off(set->crtc, *set->connectors,
+ set->num_connectors)) {
+ config->mode_changed = true;
+ } else if (set->crtc->fb != set->fb) {
/* If we have no fb then treat it as a full mode set */
if (set->crtc->fb == NULL) {
DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
@@ -8157,8 +8181,9 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
} else if (set->fb->pixel_format !=
set->crtc->fb->pixel_format) {
config->mode_changed = true;
- } else
+ } else {
config->fb_changed = true;
+ }
}
if (set->fb && (set->x != set->crtc->x || set->y != set->crtc->y))
@@ -8332,11 +8357,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
ret = intel_set_mode(set->crtc, set->mode,
set->x, set->y, set->fb);
- if (ret) {
- DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n",
- set->crtc->base.id, ret);
- goto fail;
- }
} else if (config->fb_changed) {
intel_crtc_wait_for_pending_flips(set->crtc);
@@ -8344,18 +8364,18 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
set->x, set->y, set->fb);
}
- intel_set_config_free(config);
-
- return 0;
-
+ if (ret) {
+ DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n",
+ set->crtc->base.id, ret);
fail:
- intel_set_config_restore_state(dev, config);
+ intel_set_config_restore_state(dev, config);
- /* Try to restore the config */
- if (config->mode_changed &&
- intel_set_mode(save_set.crtc, save_set.mode,
- save_set.x, save_set.y, save_set.fb))
- DRM_ERROR("failed to restore config after modeset failure\n");
+ /* Try to restore the config */
+ if (config->mode_changed &&
+ intel_set_mode(save_set.crtc, save_set.mode,
+ save_set.x, save_set.y, save_set.fb))
+ DRM_ERROR("failed to restore config after modeset failure\n");
+ }
out_config:
intel_set_config_free(config);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index fb2fbc1..70789b1 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -303,7 +303,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
#define C (((status = I915_READ_NOTRACE(ch_ctl)) & DP_AUX_CH_CTL_SEND_BUSY) == 0)
if (has_aux_irq)
done = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
- msecs_to_jiffies(10));
+ msecs_to_jiffies_timeout(10));
else
done = wait_for_atomic(C, 10) == 0;
if (!done)
@@ -702,6 +702,9 @@ intel_dp_compute_config(struct intel_encoder *encoder,
/* Walk through all bpp values. Luckily they're all nicely spaced with 2
* bpc in between. */
bpp = min_t(int, 8*3, pipe_config->pipe_bpp);
+ if (is_edp(intel_dp) && dev_priv->edp.bpp)
+ bpp = min_t(int, bpp, dev_priv->edp.bpp);
+
for (; bpp >= 6*3; bpp -= 2*3) {
mode_rate = intel_dp_link_required(target_clock, bpp);
@@ -739,6 +742,7 @@ found:
intel_dp->link_bw = bws[clock];
intel_dp->lane_count = lane_count;
adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
+ pipe_config->pipe_bpp = bpp;
pipe_config->pixel_target_clock = target_clock;
DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
@@ -751,20 +755,6 @@ found:
target_clock, adjusted_mode->clock,
&pipe_config->dp_m_n);
- /*
- * XXX: We have a strange regression where using the vbt edp bpp value
- * for the link bw computation results in black screens, the panel only
- * works when we do the computation at the usual 24bpp (but still
- * requires us to use 18bpp). Until that's fully debugged, stay
- * bug-for-bug compatible with the old code.
- */
- if (is_edp(intel_dp) && dev_priv->edp.bpp) {
- DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n",
- bpp, dev_priv->edp.bpp);
- bpp = min_t(int, bpp, dev_priv->edp.bpp);
- }
- pipe_config->pipe_bpp = bpp;
-
return true;
}
@@ -1389,6 +1379,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
ironlake_edp_panel_on(intel_dp);
ironlake_edp_panel_vdd_off(intel_dp, true);
intel_dp_complete_link_train(intel_dp);
+ intel_dp_stop_link_train(intel_dp);
ironlake_edp_backlight_on(intel_dp);
}
@@ -1711,10 +1702,9 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
struct drm_i915_private *dev_priv = dev->dev_private;
enum port port = intel_dig_port->port;
int ret;
- uint32_t temp;
if (HAS_DDI(dev)) {
- temp = I915_READ(DP_TP_CTL(port));
+ uint32_t temp = I915_READ(DP_TP_CTL(port));
if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)
temp |= DP_TP_CTL_SCRAMBLE_DISABLE;
@@ -1724,18 +1714,6 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
case DP_TRAINING_PATTERN_DISABLE:
-
- if (port != PORT_A) {
- temp |= DP_TP_CTL_LINK_TRAIN_IDLE;
- I915_WRITE(DP_TP_CTL(port), temp);
-
- if (wait_for((I915_READ(DP_TP_STATUS(port)) &
- DP_TP_STATUS_IDLE_DONE), 1))
- DRM_ERROR("Timed out waiting for DP idle patterns\n");
-
- temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
- }
-
temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
break;
@@ -1811,6 +1789,37 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
return true;
}
+static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum port port = intel_dig_port->port;
+ uint32_t val;
+
+ if (!HAS_DDI(dev))
+ return;
+
+ val = I915_READ(DP_TP_CTL(port));
+ val &= ~DP_TP_CTL_LINK_TRAIN_MASK;
+ val |= DP_TP_CTL_LINK_TRAIN_IDLE;
+ I915_WRITE(DP_TP_CTL(port), val);
+
+ /*
+ * On PORT_A we can have only eDP in SST mode. There the only reason
+ * we need to set idle transmission mode is to work around a HW issue
+ * where we enable the pipe while not in idle link-training mode.
+ * In this case there is requirement to wait for a minimum number of
+ * idle patterns to be sent.
+ */
+ if (port == PORT_A)
+ return;
+
+ if (wait_for((I915_READ(DP_TP_STATUS(port)) & DP_TP_STATUS_IDLE_DONE),
+ 1))
+ DRM_ERROR("Timed out waiting for DP idle patterns\n");
+}
+
/* Enable corresponding port and start training pattern 1 */
void
intel_dp_start_link_train(struct intel_dp *intel_dp)
@@ -1953,10 +1962,19 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
++tries;
}
+ intel_dp_set_idle_link_train(intel_dp);
+
+ intel_dp->DP = DP;
+
if (channel_eq)
DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
- intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE);
+}
+
+void intel_dp_stop_link_train(struct intel_dp *intel_dp)
+{
+ intel_dp_set_link_train(intel_dp, intel_dp->DP,
+ DP_TRAINING_PATTERN_DISABLE);
}
static void
@@ -2164,6 +2182,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
drm_get_encoder_name(&intel_encoder->base));
intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp);
+ intel_dp_stop_link_train(intel_dp);
}
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index b5b6d19..624a9e6 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -499,6 +499,7 @@ extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
extern void intel_dp_init_link_config(struct intel_dp *intel_dp);
extern void intel_dp_start_link_train(struct intel_dp *intel_dp);
extern void intel_dp_complete_link_train(struct intel_dp *intel_dp);
+extern void intel_dp_stop_link_train(struct intel_dp *intel_dp);
extern void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
extern void intel_dp_encoder_destroy(struct drm_encoder *encoder);
extern void intel_dp_check_link_status(struct intel_dp *intel_dp);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 0e19e57..6b7c3ca 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -262,10 +262,22 @@ void intel_fbdev_fini(struct drm_device *dev)
void intel_fbdev_set_suspend(struct drm_device *dev, int state)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- if (!dev_priv->fbdev)
+ struct intel_fbdev *ifbdev = dev_priv->fbdev;
+ struct fb_info *info;
+
+ if (!ifbdev)
return;
- fb_set_suspend(dev_priv->fbdev->helper.fbdev, state);
+ info = ifbdev->helper.fbdev;
+
+ /* On resume from hibernation: If the object is shmemfs backed, it has
+ * been restored from swap. If the object is stolen however, it will be
+ * full of whatever garbage was left in there.
+ */
+ if (!state && ifbdev->ifb.obj->stolen)
+ memset_io(info->screen_base, 0, info->screen_size);
+
+ fb_set_suspend(info, state);
}
MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 5d245031..639fe19 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -228,7 +228,7 @@ gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
* need to wake up periodically and check that ourselves. */
I915_WRITE(GMBUS4 + reg_offset, gmbus4_irq_en);
- for (i = 0; i < msecs_to_jiffies(50) + 1; i++) {
+ for (i = 0; i < msecs_to_jiffies_timeout(50); i++) {
prepare_to_wait(&dev_priv->gmbus_wait_queue, &wait,
TASK_UNINTERRUPTIBLE);
@@ -263,7 +263,8 @@ gmbus_wait_idle(struct drm_i915_private *dev_priv)
/* Important: The hw handles only the first bit, so set only one! */
I915_WRITE(GMBUS4 + reg_offset, GMBUS_IDLE_EN);
- ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C, 10);
+ ret = wait_event_timeout(dev_priv->gmbus_wait_queue, C,
+ msecs_to_jiffies_timeout(10));
I915_WRITE(GMBUS4 + reg_offset, 0);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index f36f1ba..29412cc 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -815,10 +815,10 @@ static const struct dmi_system_id intel_no_lvds[] = {
},
{
.callback = intel_no_lvds_dmi_callback,
- .ident = "Hewlett-Packard HP t5740e Thin Client",
+ .ident = "Hewlett-Packard HP t5740",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP t5740e Thin Client"),
+ DMI_MATCH(DMI_PRODUCT_NAME, " t5740"),
},
},
{
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index de3b0dc..aa01128 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -1301,17 +1301,17 @@ static void valleyview_update_wm(struct drm_device *dev)
vlv_update_drain_latency(dev);
- if (g4x_compute_wm0(dev, 0,
+ if (g4x_compute_wm0(dev, PIPE_A,
&valleyview_wm_info, latency_ns,
&valleyview_cursor_wm_info, latency_ns,
&planea_wm, &cursora_wm))
- enabled |= 1;
+ enabled |= 1 << PIPE_A;
- if (g4x_compute_wm0(dev, 1,
+ if (g4x_compute_wm0(dev, PIPE_B,
&valleyview_wm_info, latency_ns,
&valleyview_cursor_wm_info, latency_ns,
&planeb_wm, &cursorb_wm))
- enabled |= 2;
+ enabled |= 1 << PIPE_B;
if (single_plane_enabled(enabled) &&
g4x_compute_srwm(dev, ffs(enabled) - 1,
@@ -1357,17 +1357,17 @@ static void g4x_update_wm(struct drm_device *dev)
int plane_sr, cursor_sr;
unsigned int enabled = 0;
- if (g4x_compute_wm0(dev, 0,
+ if (g4x_compute_wm0(dev, PIPE_A,
&g4x_wm_info, latency_ns,
&g4x_cursor_wm_info, latency_ns,
&planea_wm, &cursora_wm))
- enabled |= 1;
+ enabled |= 1 << PIPE_A;
- if (g4x_compute_wm0(dev, 1,
+ if (g4x_compute_wm0(dev, PIPE_B,
&g4x_wm_info, latency_ns,
&g4x_cursor_wm_info, latency_ns,
&planeb_wm, &cursorb_wm))
- enabled |= 2;
+ enabled |= 1 << PIPE_B;
if (single_plane_enabled(enabled) &&
g4x_compute_srwm(dev, ffs(enabled) - 1,
@@ -1716,7 +1716,7 @@ static void ironlake_update_wm(struct drm_device *dev)
unsigned int enabled;
enabled = 0;
- if (g4x_compute_wm0(dev, 0,
+ if (g4x_compute_wm0(dev, PIPE_A,
&ironlake_display_wm_info,
ILK_LP0_PLANE_LATENCY,
&ironlake_cursor_wm_info,
@@ -1727,10 +1727,10 @@ static void ironlake_update_wm(struct drm_device *dev)
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n",
plane_wm, cursor_wm);
- enabled |= 1;
+ enabled |= 1 << PIPE_A;
}
- if (g4x_compute_wm0(dev, 1,
+ if (g4x_compute_wm0(dev, PIPE_B,
&ironlake_display_wm_info,
ILK_LP0_PLANE_LATENCY,
&ironlake_cursor_wm_info,
@@ -1741,7 +1741,7 @@ static void ironlake_update_wm(struct drm_device *dev)
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n",
plane_wm, cursor_wm);
- enabled |= 2;
+ enabled |= 1 << PIPE_B;
}
/*
@@ -1801,7 +1801,7 @@ static void sandybridge_update_wm(struct drm_device *dev)
unsigned int enabled;
enabled = 0;
- if (g4x_compute_wm0(dev, 0,
+ if (g4x_compute_wm0(dev, PIPE_A,
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
@@ -1812,10 +1812,10 @@ static void sandybridge_update_wm(struct drm_device *dev)
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n",
plane_wm, cursor_wm);
- enabled |= 1;
+ enabled |= 1 << PIPE_A;
}
- if (g4x_compute_wm0(dev, 1,
+ if (g4x_compute_wm0(dev, PIPE_B,
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
@@ -1826,7 +1826,7 @@ static void sandybridge_update_wm(struct drm_device *dev)
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n",
plane_wm, cursor_wm);
- enabled |= 2;
+ enabled |= 1 << PIPE_B;
}
/*
@@ -1904,7 +1904,7 @@ static void ivybridge_update_wm(struct drm_device *dev)
unsigned int enabled;
enabled = 0;
- if (g4x_compute_wm0(dev, 0,
+ if (g4x_compute_wm0(dev, PIPE_A,
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
@@ -1915,10 +1915,10 @@ static void ivybridge_update_wm(struct drm_device *dev)
DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
" plane %d, " "cursor: %d\n",
plane_wm, cursor_wm);
- enabled |= 1;
+ enabled |= 1 << PIPE_A;
}
- if (g4x_compute_wm0(dev, 1,
+ if (g4x_compute_wm0(dev, PIPE_B,
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
@@ -1929,10 +1929,10 @@ static void ivybridge_update_wm(struct drm_device *dev)
DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
" plane %d, cursor: %d\n",
plane_wm, cursor_wm);
- enabled |= 2;
+ enabled |= 1 << PIPE_B;
}
- if (g4x_compute_wm0(dev, 2,
+ if (g4x_compute_wm0(dev, PIPE_C,
&sandybridge_display_wm_info, latency,
&sandybridge_cursor_wm_info, latency,
&plane_wm, &cursor_wm)) {
@@ -1943,7 +1943,7 @@ static void ivybridge_update_wm(struct drm_device *dev)
DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
" plane %d, cursor: %d\n",
plane_wm, cursor_wm);
- enabled |= 3;
+ enabled |= 1 << PIPE_C;
}
/*
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index d154284..d4ea6c2 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1776,11 +1776,14 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
* Assume that the preferred modes are
* arranged in priority order.
*/
- intel_ddc_get_modes(connector, intel_sdvo->i2c);
- if (list_empty(&connector->probed_modes) == false)
- goto end;
+ intel_ddc_get_modes(connector, &intel_sdvo->ddc);
- /* Fetch modes from VBT */
+ /*
+ * Fetch modes from VBT. For SDVO prefer the VBT mode since some
+ * SDVO->LVDS transcoders can't cope with the EDID mode. Since
+ * drm_mode_probed_add adds the mode at the head of the list we add it
+ * last.
+ */
if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
newmode = drm_mode_duplicate(connector->dev,
dev_priv->sdvo_lvds_vbt_mode);
@@ -1792,7 +1795,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
}
}
-end:
list_for_each_entry(newmode, &connector->probed_modes, head) {
if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
intel_sdvo->sdvo_lvds_fixed_mode =
@@ -2790,12 +2792,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915;
}
- /* Only enable the hotplug irq if we need it, to work around noisy
- * hotplug lines.
- */
- if (intel_sdvo->hotplug_active)
- intel_encoder->hpd_pin = HPD_SDVO_B ? HPD_SDVO_B : HPD_SDVO_C;
-
intel_encoder->compute_config = intel_sdvo_compute_config;
intel_encoder->disable = intel_disable_sdvo;
intel_encoder->mode_set = intel_sdvo_mode_set;
@@ -2814,6 +2810,14 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
goto err_output;
}
+ /* Only enable the hotplug irq if we need it, to work around noisy
+ * hotplug lines.
+ */
+ if (intel_sdvo->hotplug_active) {
+ intel_encoder->hpd_pin =
+ intel_sdvo->is_sdvob ? HPD_SDVO_B : HPD_SDVO_C;
+ }
+
/*
* Cloning SDVO with anything is often impossible, since the SDVO
* encoder can request a special input timing mode. And even if that's
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index f988965..ee66bad 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -46,29 +46,26 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
static inline void mga_wait_vsync(struct mga_device *mdev)
{
- unsigned int count = 0;
+ unsigned long timeout = jiffies + HZ/10;
unsigned int status = 0;
do {
status = RREG32(MGAREG_Status);
- count++;
- } while ((status & 0x08) && (count < 250000));
- count = 0;
+ } while ((status & 0x08) && time_before(jiffies, timeout));
+ timeout = jiffies + HZ/10;
status = 0;
do {
status = RREG32(MGAREG_Status);
- count++;
- } while (!(status & 0x08) && (count < 250000));
+ } while (!(status & 0x08) && time_before(jiffies, timeout));
}
static inline void mga_wait_busy(struct mga_device *mdev)
{
- unsigned int count = 0;
+ unsigned long timeout = jiffies + HZ;
unsigned int status = 0;
do {
status = RREG8(MGAREG_Status + 2);
- count++;
- } while ((status & 0x01) && (count < 500000));
+ } while ((status & 0x01) && time_before(jiffies, timeout));
}
/*
@@ -189,12 +186,12 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp);
+ WREG8(DAC_DATA, tmp);
WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_REMHEADCTL_CLKDIS;
- WREG_DAC(MGA1064_REMHEADCTL, tmp);
+ WREG8(DAC_DATA, tmp);
/* select PLL Set C */
tmp = RREG8(MGAREG_MEM_MISC_READ);
@@ -204,7 +201,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
udelay(500);
@@ -212,7 +209,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_VREF_CTL);
tmp = RREG8(DAC_DATA);
tmp &= ~0x04;
- WREG_DAC(MGA1064_VREF_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
udelay(50);
@@ -236,13 +233,13 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
- WREG_DAC(MGA1064_REMHEADCTL, tmp);
+ WREG8(DAC_DATA, tmp);
/* reset dotclock rate bit */
WREG8(MGAREG_SEQ_INDEX, 1);
@@ -253,7 +250,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
vcount = RREG8(MGAREG_VCOUNT);
@@ -318,7 +315,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp);
+ WREG8(DAC_DATA, tmp);
tmp = RREG8(MGAREG_MEM_MISC_READ);
tmp |= 0x3 << 2;
@@ -326,12 +323,12 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
tmp = RREG8(DAC_DATA);
- WREG_DAC(MGA1064_PIX_PLL_STAT, tmp & ~0x40);
+ WREG8(DAC_DATA, tmp & ~0x40);
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
WREG_DAC(MGA1064_EV_PIX_PLLC_M, m);
WREG_DAC(MGA1064_EV_PIX_PLLC_N, n);
@@ -342,7 +339,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
udelay(500);
@@ -350,11 +347,11 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
tmp = RREG8(DAC_DATA);
- WREG_DAC(MGA1064_PIX_PLL_STAT, tmp | 0x40);
+ WREG8(DAC_DATA, tmp | 0x40);
tmp = RREG8(MGAREG_MEM_MISC_READ);
tmp |= (0x3 << 2);
@@ -363,7 +360,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
return 0;
}
@@ -416,7 +413,7 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp);
+ WREG8(DAC_DATA, tmp);
tmp = RREG8(MGAREG_MEM_MISC_READ);
tmp |= 0x3 << 2;
@@ -425,7 +422,7 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
udelay(500);
@@ -439,13 +436,13 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
vcount = RREG8(MGAREG_VCOUNT);
@@ -515,12 +512,12 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
- WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp);
+ WREG8(DAC_DATA, tmp);
WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
tmp = RREG8(DAC_DATA);
tmp |= MGA1064_REMHEADCTL_CLKDIS;
- WREG_DAC(MGA1064_REMHEADCTL, tmp);
+ WREG8(DAC_DATA, tmp);
tmp = RREG8(MGAREG_MEM_MISC_READ);
tmp |= (0x3<<2) | 0xc0;
@@ -530,7 +527,7 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
tmp = RREG8(DAC_DATA);
tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
- WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+ WREG8(DAC_DATA, tmp);
udelay(500);
@@ -657,12 +654,26 @@ static void mga_g200wb_commit(struct drm_crtc *crtc)
WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
}
-
+/*
+ This is how the framebuffer base address is stored in g200 cards:
+ * Assume @offset is the gpu_addr variable of the framebuffer object
+ * Then addr is the number of _pixels_ (not bytes) from the start of
+ VRAM to the first pixel we want to display. (divided by 2 for 32bit
+ framebuffers)
+ * addr is stored in the CRTCEXT0, CRTCC and CRTCD registers
+ addr<20> -> CRTCEXT0<6>
+ addr<19-16> -> CRTCEXT0<3-0>
+ addr<15-8> -> CRTCC<7-0>
+ addr<7-0> -> CRTCD<7-0>
+ CRTCEXT0 has to be programmed last to trigger an update and make the
+ new addr variable take effect.
+ */
void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
{
struct mga_device *mdev = crtc->dev->dev_private;
u32 addr;
int count;
+ u8 crtcext0;
while (RREG8(0x1fda) & 0x08);
while (!(RREG8(0x1fda) & 0x08));
@@ -670,10 +681,17 @@ void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
count = RREG8(MGAREG_VCOUNT) + 2;
while (RREG8(MGAREG_VCOUNT) < count);
- addr = offset >> 2;
+ WREG8(MGAREG_CRTCEXT_INDEX, 0);
+ crtcext0 = RREG8(MGAREG_CRTCEXT_DATA);
+ crtcext0 &= 0xB0;
+ addr = offset / 8;
+ /* Can't store addresses any higher than that...
+ but we also don't have more than 16MB of memory, so it should be fine. */
+ WARN_ON(addr > 0x1fffff);
+ crtcext0 |= (!!(addr & (1<<20)))<<6;
WREG_CRT(0x0d, (u8)(addr & 0xff));
WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff);
- WREG_CRT(0xaf, (u8)(addr >> 16) & 0xf);
+ WREG_ECRT(0x0, ((u8)(addr >> 16) & 0xf) | crtcext0);
}
@@ -829,11 +847,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
for (i = 0; i < sizeof(dacvalue); i++) {
- if ((i <= 0x03) ||
- (i == 0x07) ||
- (i == 0x0b) ||
- (i == 0x0f) ||
- ((i >= 0x13) && (i <= 0x17)) ||
+ if ((i <= 0x17) ||
(i == 0x1b) ||
(i == 0x1c) ||
((i >= 0x1f) && (i <= 0x29)) ||
@@ -1020,13 +1034,14 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
else
hi_pri_lvl = 5;
- WREG8(0x1fde, 0x06);
- WREG8(0x1fdf, hi_pri_lvl);
+ WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
+ WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl);
} else {
+ WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
if (mdev->reg_1e24 >= 0x01)
- WREG8(0x1fdf, 0x03);
+ WREG8(MGAREG_CRTCEXT_DATA, 0x03);
else
- WREG8(0x1fdf, 0x04);
+ WREG8(MGAREG_CRTCEXT_DATA, 0x04);
}
}
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
index 955af12..a36e64e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
@@ -138,7 +138,6 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
break;
case 0xce:
@@ -225,7 +224,6 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
break;
case 0xc8:
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
index d0817d9..f02fd9f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
@@ -50,11 +50,16 @@ nv50_dac_sense(struct nv50_disp_priv *priv, int or, u32 loadval)
{
const u32 doff = (or * 0x800);
int load = -EINVAL;
+ nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
+ nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
- udelay(9500);
+ mdelay(9);
+ udelay(500);
nv_wr32(priv, 0x61a00c + doff, 0x80000000);
load = (nv_rd32(priv, 0x61a00c + doff) & 0x38000000) >> 27;
nv_wr32(priv, 0x61a00c + doff, 0x00000000);
+ nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
+ nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
return load;
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
index 0d36bdc..7fdade6 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
@@ -55,6 +55,10 @@ nv84_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data)
nv_wr32(priv, 0x616510 + hoff, 0x00000000);
nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001);
+ nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
+ nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
+ nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
+
/* ??? */
nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
index ddaeb55..e9b8217 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
@@ -40,8 +40,8 @@
* FIFO channel objects
******************************************************************************/
-void
-nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
+static void
+nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv)
{
struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_gpuobj *cur;
@@ -62,6 +62,14 @@ nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
nv_wr32(priv, 0x002500, 0x00000101);
}
+void
+nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
+{
+ mutex_lock(&nv_subdev(priv)->mutex);
+ nv50_fifo_playlist_update_locked(priv);
+ mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
static int
nv50_fifo_context_attach(struct nouveau_object *parent,
struct nouveau_object *object)
@@ -487,7 +495,7 @@ nv50_fifo_init(struct nouveau_object *object)
for (i = 0; i < 128; i++)
nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
- nv50_fifo_playlist_update(priv);
+ nv50_fifo_playlist_update_locked(priv);
nv_wr32(priv, 0x003200, 0x00000001);
nv_wr32(priv, 0x003250, 0x00000001);
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
index 4d4a6b9..46dfa68 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
@@ -71,6 +71,7 @@ nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv)
struct nouveau_gpuobj *cur;
int i, p;
+ mutex_lock(&nv_subdev(priv)->mutex);
cur = priv->playlist[priv->cur_playlist];
priv->cur_playlist = !priv->cur_playlist;
@@ -87,6 +88,7 @@ nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv)
nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000))
nv_error(priv, "playlist update failed\n");
+ mutex_unlock(&nv_subdev(priv)->mutex);
}
static int
@@ -248,9 +250,17 @@ nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
struct nvc0_fifo_priv *priv = (void *)object->engine;
struct nvc0_fifo_chan *chan = (void *)object;
u32 chid = chan->base.chid;
+ u32 mask, engine;
nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
nvc0_fifo_playlist_update(priv);
+ mask = nv_rd32(priv, 0x0025a4);
+ for (engine = 0; mask && engine < 16; engine++) {
+ if (!(mask & (1 << engine)))
+ continue;
+ nv_mask(priv, 0x0025a8 + (engine * 4), 0x00000000, 0x00000000);
+ mask &= ~(1 << engine);
+ }
nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
return nouveau_fifo_channel_fini(&chan->base, suspend);
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index 9151919..56192a7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -94,11 +94,13 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
u32 match = (engine << 16) | 0x00000001;
int i, p;
+ mutex_lock(&nv_subdev(priv)->mutex);
cur = engn->playlist[engn->cur_playlist];
if (unlikely(cur == NULL)) {
int ret = nouveau_gpuobj_new(nv_object(priv), NULL,
0x8000, 0x1000, 0, &cur);
if (ret) {
+ mutex_unlock(&nv_subdev(priv)->mutex);
nv_error(priv, "playlist alloc failed\n");
return;
}
@@ -122,6 +124,7 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
nv_error(priv, "playlist %d update timeout\n", engine);
+ mutex_unlock(&nv_subdev(priv)->mutex);
}
static int
diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h
index 0a393f7..5a5961b 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/class.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/class.h
@@ -218,7 +218,7 @@ struct nv04_display_class {
#define NV50_DISP_DAC_PWR_STATE 0x00000040
#define NV50_DISP_DAC_PWR_STATE_ON 0x00000000
#define NV50_DISP_DAC_PWR_STATE_OFF 0x00000040
-#define NV50_DISP_DAC_LOAD 0x0002000c
+#define NV50_DISP_DAC_LOAD 0x00020100
#define NV50_DISP_DAC_LOAD_VALUE 0x00000007
#define NV50_DISP_PIOR_MTHD 0x00030000
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
index c300b5e..c434d39 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
@@ -1940,8 +1940,8 @@ init_zm_mask_add(struct nvbios_init *init)
trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add);
init->offset += 13;
- data = init_rd32(init, addr) & mask;
- data |= ((data + add) & ~mask);
+ data = init_rd32(init, addr);
+ data = (data & mask) | ((data + add) & ~mask);
init_wr32(init, addr, data);
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
index e4940fb..fb794e9 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
@@ -29,7 +29,6 @@
struct nvc0_ltcg_priv {
struct nouveau_ltcg base;
u32 part_nr;
- u32 part_mask;
u32 subp_nr;
struct nouveau_mm tags;
u32 num_tags;
@@ -105,8 +104,6 @@ nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count)
/* wait until it's finished with clearing */
for (p = 0; p < priv->part_nr; ++p) {
- if (!(priv->part_mask & (1 << p)))
- continue;
for (i = 0; i < priv->subp_nr; ++i)
nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0);
}
@@ -121,6 +118,8 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
int ret;
nv_wr32(priv, 0x17e8d8, priv->part_nr);
+ if (nv_device(pfb)->card_type >= NV_E0)
+ nv_wr32(priv, 0x17e000, priv->part_nr);
/* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
priv->num_tags = (pfb->ram.size >> 17) / 4;
@@ -167,16 +166,20 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
{
struct nvc0_ltcg_priv *priv;
struct nouveau_fb *pfb = nouveau_fb(parent);
- int ret;
+ u32 parts, mask;
+ int ret, i;
ret = nouveau_ltcg_create(parent, engine, oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
- priv->part_nr = nv_rd32(priv, 0x022438);
- priv->part_mask = nv_rd32(priv, 0x022554);
-
+ parts = nv_rd32(priv, 0x022438);
+ mask = nv_rd32(priv, 0x022554);
+ for (i = 0; i < parts; i++) {
+ if (!(mask & (1 << i)))
+ priv->part_nr++;
+ }
priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28;
nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 7bf22d4..f17dc2a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -638,17 +638,8 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
}
s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
- if (s->event) {
- struct drm_pending_vblank_event *e = s->event;
- struct timeval now;
-
- do_gettimeofday(&now);
- e->event.sequence = 0;
- e->event.tv_sec = now.tv_sec;
- e->event.tv_usec = now.tv_usec;
- list_add_tail(&e->base.link, &e->base.file_priv->event_list);
- wake_up_interruptible(&e->base.file_priv->event_wait);
- }
+ if (s->event)
+ drm_send_vblank_event(dev, -1, s->event);
list_del(&s->head);
if (ps)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 46c152f..383f4e6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -453,18 +453,32 @@ nouveau_do_suspend(struct drm_device *dev)
NV_INFO(drm, "evicting buffers...\n");
ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM);
+ NV_INFO(drm, "waiting for kernel channels to go idle...\n");
+ if (drm->cechan) {
+ ret = nouveau_channel_idle(drm->cechan);
+ if (ret)
+ return ret;
+ }
+
+ if (drm->channel) {
+ ret = nouveau_channel_idle(drm->channel);
+ if (ret)
+ return ret;
+ }
+
+ NV_INFO(drm, "suspending client object trees...\n");
if (drm->fence && nouveau_fence(drm)->suspend) {
if (!nouveau_fence(drm)->suspend(drm))
return -ENOMEM;
}
- NV_INFO(drm, "suspending client object trees...\n");
list_for_each_entry(cli, &drm->clients, head) {
ret = nouveau_client_fini(&cli->base, true);
if (ret)
goto fail_client;
}
+ NV_INFO(drm, "suspending kernel object tree...\n");
ret = nouveau_client_fini(&drm->client.base, true);
if (ret)
goto fail_client;
@@ -514,17 +528,18 @@ nouveau_do_resume(struct drm_device *dev)
nouveau_agp_reset(drm);
- NV_INFO(drm, "resuming client object trees...\n");
+ NV_INFO(drm, "resuming kernel object tree...\n");
nouveau_client_init(&drm->client.base);
nouveau_agp_init(drm);
+ NV_INFO(drm, "resuming client object trees...\n");
+ if (drm->fence && nouveau_fence(drm)->resume)
+ nouveau_fence(drm)->resume(drm);
+
list_for_each_entry(cli, &drm->clients, head) {
nouveau_client_init(&cli->base);
}
- if (drm->fence && nouveau_fence(drm)->resume)
- nouveau_fence(drm)->resume(drm);
-
nouveau_run_vbios_init(dev);
nouveau_pm_resume(dev);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index ebf0a68..dd5e01f 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -1554,7 +1554,9 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{
struct nv50_disp *disp = nv50_disp(encoder->dev);
int ret, or = nouveau_encoder(encoder)->or;
- u32 load = 0;
+ u32 load = nouveau_drm(encoder->dev)->vbios.dactestval;
+ if (load == 0)
+ load = 340;
ret = nv_exec(disp->core, NV50_DISP_DAC_LOAD + or, &load, sizeof(load));
if (ret || load != 7)
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 9c53c25..826586f 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -649,6 +649,9 @@ static void pdev_shutdown(struct platform_device *device)
static int pdev_probe(struct platform_device *device)
{
+ if (omapdss_is_initialized() == false)
+ return -EPROBE_DEFER;
+
DBG("%s", device->name);
return drm_platform_init(&omap_drm_driver, device);
}
diff --git a/drivers/gpu/drm/qxl/Kconfig b/drivers/gpu/drm/qxl/Kconfig
index 2f1a57e..d6c1279 100644
--- a/drivers/gpu/drm/qxl/Kconfig
+++ b/drivers/gpu/drm/qxl/Kconfig
@@ -4,6 +4,7 @@ config DRM_QXL
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
+ select FB_DEFERRED_IO
select DRM_KMS_HELPER
select DRM_TTM
help
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index 08b0823..f867714 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -277,7 +277,7 @@ out_unref:
return 0;
}
-static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port)
+static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port, bool intr)
{
int irq_num;
long addr = qdev->io_base + port;
@@ -285,20 +285,29 @@ static int wait_for_io_cmd_user(struct qxl_device *qdev, uint8_t val, long port)
mutex_lock(&qdev->async_io_mutex);
irq_num = atomic_read(&qdev->irq_received_io_cmd);
-
-
if (qdev->last_sent_io_cmd > irq_num) {
- ret = wait_event_interruptible(qdev->io_cmd_event,
- atomic_read(&qdev->irq_received_io_cmd) > irq_num);
- if (ret)
+ if (intr)
+ ret = wait_event_interruptible_timeout(qdev->io_cmd_event,
+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ);
+ else
+ ret = wait_event_timeout(qdev->io_cmd_event,
+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ);
+ /* 0 is timeout, just bail the "hw" has gone away */
+ if (ret <= 0)
goto out;
irq_num = atomic_read(&qdev->irq_received_io_cmd);
}
outb(val, addr);
qdev->last_sent_io_cmd = irq_num + 1;
- ret = wait_event_interruptible(qdev->io_cmd_event,
- atomic_read(&qdev->irq_received_io_cmd) > irq_num);
+ if (intr)
+ ret = wait_event_interruptible_timeout(qdev->io_cmd_event,
+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ);
+ else
+ ret = wait_event_timeout(qdev->io_cmd_event,
+ atomic_read(&qdev->irq_received_io_cmd) > irq_num, 5*HZ);
out:
+ if (ret > 0)
+ ret = 0;
mutex_unlock(&qdev->async_io_mutex);
return ret;
}
@@ -308,7 +317,7 @@ static void wait_for_io_cmd(struct qxl_device *qdev, uint8_t val, long port)
int ret;
restart:
- ret = wait_for_io_cmd_user(qdev, val, port);
+ ret = wait_for_io_cmd_user(qdev, val, port, false);
if (ret == -ERESTARTSYS)
goto restart;
}
@@ -340,7 +349,7 @@ int qxl_io_update_area(struct qxl_device *qdev, struct qxl_bo *surf,
mutex_lock(&qdev->update_area_mutex);
qdev->ram_header->update_area = *area;
qdev->ram_header->update_surface = surface_id;
- ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC);
+ ret = wait_for_io_cmd_user(qdev, 0, QXL_IO_UPDATE_AREA_ASYNC, true);
mutex_unlock(&qdev->update_area_mutex);
return ret;
}
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index fcfd443..823d29e 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -428,10 +428,10 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
int inc = 1;
qobj = gem_to_qxl_bo(qxl_fb->obj);
- if (qxl_fb != qdev->active_user_framebuffer) {
- DRM_INFO("%s: qxl_fb 0x%p != qdev->active_user_framebuffer 0x%p\n",
- __func__, qxl_fb, qdev->active_user_framebuffer);
- }
+ /* if we aren't primary surface ignore this */
+ if (!qobj->is_primary)
+ return 0;
+
if (!num_clips) {
num_clips = 1;
clips = &norect;
@@ -604,7 +604,6 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
mode->hdisplay,
mode->vdisplay);
}
- qdev->mode_set = true;
return 0;
}
@@ -893,7 +892,6 @@ qxl_user_framebuffer_create(struct drm_device *dev,
{
struct drm_gem_object *obj;
struct qxl_framebuffer *qxl_fb;
- struct qxl_device *qdev = dev->dev_private;
int ret;
obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
@@ -909,13 +907,6 @@ qxl_user_framebuffer_create(struct drm_device *dev,
return NULL;
}
- if (qdev->active_user_framebuffer) {
- DRM_INFO("%s: active_user_framebuffer %p -> %p\n",
- __func__,
- qdev->active_user_framebuffer, qxl_fb);
- }
- qdev->active_user_framebuffer = qxl_fb;
-
return &qxl_fb->base;
}
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 52b582c..43d06ab 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -255,12 +255,6 @@ struct qxl_device {
struct qxl_gem gem;
struct qxl_mode_info mode_info;
- /*
- * last created framebuffer with fb_create
- * only used by debugfs dumbppm
- */
- struct qxl_framebuffer *active_user_framebuffer;
-
struct fb_info *fbdev_info;
struct qxl_framebuffer *fbdev_qfb;
void *ram_physical;
@@ -270,7 +264,6 @@ struct qxl_device {
struct qxl_ring *cursor_ring;
struct qxl_ram_header *ram_header;
- bool mode_set;
bool primary_created;
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index 04b64f9..a4b71b2 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -151,7 +151,7 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
struct qxl_bo *cmd_bo;
int release_type;
struct drm_qxl_command *commands =
- (struct drm_qxl_command *)execbuffer->commands;
+ (struct drm_qxl_command *)(uintptr_t)execbuffer->commands;
if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num],
sizeof(user_cmd)))
@@ -193,7 +193,7 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
for (i = 0 ; i < user_cmd.relocs_num; ++i) {
if (DRM_COPY_FROM_USER(&reloc,
- &((struct drm_qxl_reloc *)user_cmd.relocs)[i],
+ &((struct drm_qxl_reloc *)(uintptr_t)user_cmd.relocs)[i],
sizeof(reloc))) {
qxl_bo_list_unreserve(&reloc_list, true);
qxl_release_unreserve(qdev, release);
@@ -294,6 +294,7 @@ static int qxl_update_area_ioctl(struct drm_device *dev, void *data,
goto out;
if (!qobj->pin_count) {
+ qxl_ttm_placement_from_domain(qobj, qobj->type);
ret = ttm_bo_validate(&qobj->tbo, &qobj->placement,
true, false);
if (unlikely(ret))
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index 85127ed..e27ce2a 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -128,12 +128,13 @@ int qxl_device_init(struct qxl_device *qdev,
qdev->vram_mapping = io_mapping_create_wc(qdev->vram_base, pci_resource_len(pdev, 0));
qdev->surface_mapping = io_mapping_create_wc(qdev->surfaceram_base, qdev->surfaceram_size);
- DRM_DEBUG_KMS("qxl: vram %p-%p(%dM %dk), surface %p-%p(%dM %dk)\n",
- (void *)qdev->vram_base, (void *)pci_resource_end(pdev, 0),
+ DRM_DEBUG_KMS("qxl: vram %llx-%llx(%dM %dk), surface %llx-%llx(%dM %dk)\n",
+ (unsigned long long)qdev->vram_base,
+ (unsigned long long)pci_resource_end(pdev, 0),
(int)pci_resource_len(pdev, 0) / 1024 / 1024,
(int)pci_resource_len(pdev, 0) / 1024,
- (void *)qdev->surfaceram_base,
- (void *)pci_resource_end(pdev, 1),
+ (unsigned long long)qdev->surfaceram_base,
+ (unsigned long long)pci_resource_end(pdev, 1),
(int)qdev->surfaceram_size / 1024 / 1024,
(int)qdev->surfaceram_size / 1024);
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 6d6fdb3..d5df8fd 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1811,12 +1811,9 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
static void atombios_crtc_prepare(struct drm_crtc *crtc)
{
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
- radeon_crtc->in_mode_set = true;
-
/* disable crtc pair power gating before programming */
if (ASIC_IS_DCE6(rdev))
atombios_powergate_crtc(crtc, ATOM_DISABLE);
@@ -1827,11 +1824,8 @@ static void atombios_crtc_prepare(struct drm_crtc *crtc)
static void atombios_crtc_commit(struct drm_crtc *crtc)
{
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
-
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
atombios_lock_crtc(crtc, ATOM_DISABLE);
- radeon_crtc->in_mode_set = false;
}
static void atombios_crtc_disable(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 44a7da6..8406c82 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -667,6 +667,8 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
int
atombios_get_encoder_mode(struct drm_encoder *encoder)
{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
@@ -693,7 +695,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
- radeon_audio)
+ radeon_audio &&
+ !ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */
return ATOM_ENCODER_MODE_HDMI;
else if (radeon_connector->use_digital)
return ATOM_ENCODER_MODE_DVI;
@@ -704,7 +707,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
case DRM_MODE_CONNECTOR_HDMIA:
default:
if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
- radeon_audio)
+ radeon_audio &&
+ !ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */
return ATOM_ENCODER_MODE_HDMI;
else
return ATOM_ENCODER_MODE_DVI;
@@ -718,7 +722,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
return ATOM_ENCODER_MODE_DP;
else if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
- radeon_audio)
+ radeon_audio &&
+ !ASIC_IS_DCE6(rdev)) /* remove once we support DCE6 */
return ATOM_ENCODER_MODE_HDMI;
else
return ATOM_ENCODER_MODE_DVI;
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 105bafb..0f89ce3 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2343,11 +2343,13 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
u32 crtc_enabled, tmp, frame_count, blackout;
int i, j;
- save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
- save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
+ if (!ASIC_IS_NODCE(rdev)) {
+ save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
+ save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
- /* disable VGA render */
- WREG32(VGA_RENDER_CONTROL, 0);
+ /* disable VGA render */
+ WREG32(VGA_RENDER_CONTROL, 0);
+ }
/* blank the display controllers */
for (i = 0; i < rdev->num_crtc; i++) {
crtc_enabled = RREG32(EVERGREEN_CRTC_CONTROL + crtc_offsets[i]) & EVERGREEN_CRTC_MASTER_EN;
@@ -2438,8 +2440,11 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + crtc_offsets[i],
(u32)rdev->mc.vram_start);
}
- WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
- WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
+
+ if (!ASIC_IS_NODCE(rdev)) {
+ WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start));
+ WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start);
+ }
/* unlock regs and wait for update */
for (i = 0; i < rdev->num_crtc; i++) {
@@ -2499,10 +2504,12 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
}
}
}
- /* Unlock vga access */
- WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
- mdelay(1);
- WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
+ if (!ASIC_IS_NODCE(rdev)) {
+ /* Unlock vga access */
+ WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
+ mdelay(1);
+ WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
+ }
}
void evergreen_mc_program(struct radeon_device *rdev)
@@ -3405,8 +3412,8 @@ int evergreen_mc_init(struct radeon_device *rdev)
rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE);
} else {
/* size in MB on evergreen/cayman/tn */
- rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
- rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
+ rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
}
rdev->mc.visible_vram_size = rdev->mc.aper_size;
r700_vram_gtt_location(rdev, &rdev->mc);
@@ -4747,6 +4754,12 @@ static int evergreen_startup(struct radeon_device *rdev)
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r = r600_irq_init(rdev);
if (r) {
DRM_ERROR("radeon: IH init failed (%d).\n", r);
@@ -4916,10 +4929,6 @@ int evergreen_init(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
-
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
@@ -4992,8 +5001,7 @@ void evergreen_fini(struct radeon_device *rdev)
void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
{
- u32 link_width_cntl, speed_cntl, mask;
- int ret;
+ u32 link_width_cntl, speed_cntl;
if (radeon_pcie_gen2 == 0)
return;
@@ -5008,11 +5016,8 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
if (ASIC_IS_X2(rdev))
return;
- ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask);
- if (ret != 0)
- return;
-
- if (!(mask & DRM_PCIE_SPEED_50))
+ if ((rdev->pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) &&
+ (rdev->pdev->bus->max_bus_speed != PCIE_SPEED_8_0GT))
return;
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index b4ab8ce..ed7c8a7 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -154,19 +154,18 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
- u32 base_rate = 48000;
+ u32 base_rate = 24000;
if (!dig || !dig->afmt)
return;
- /* XXX: properly calculate this */
/* XXX two dtos; generally use dto0 for hdmi */
/* Express [24MHz / target pixel clock] as an exact rational
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
*/
- WREG32(DCCG_AUDIO_DTO0_PHASE, (base_rate*50) & 0xffffff);
- WREG32(DCCG_AUDIO_DTO0_MODULE, (clock*100) & 0xffffff);
+ WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
+ WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
}
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 7969c0c..8458330 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -2025,6 +2025,12 @@ static int cayman_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r = r600_irq_init(rdev);
if (r) {
DRM_ERROR("radeon: IH init failed (%d).\n", r);
@@ -2190,10 +2196,6 @@ int cayman_init(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
-
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 1024 * 1024);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 4973bff..d0314ec 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -3869,6 +3869,12 @@ static int r100_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r100_irq_set(rdev);
rdev->config.r100.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
/* 1M ring buffer */
@@ -4024,9 +4030,6 @@ int r100_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index c60350e..b9b776f 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -1382,6 +1382,12 @@ static int r300_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r100_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
/* 1M ring buffer */
@@ -1516,9 +1522,6 @@ int r300_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
diff --git a/drivers/gpu/drm/radeon/r300_cmdbuf.c b/drivers/gpu/drm/radeon/r300_cmdbuf.c
index 865e2c9..60170ea 100644
--- a/drivers/gpu/drm/radeon/r300_cmdbuf.c
+++ b/drivers/gpu/drm/radeon/r300_cmdbuf.c
@@ -75,7 +75,7 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
OUT_RING(CP_PACKET0(R300_RE_CLIPRECT_TL_0, nr * 2 - 1));
for (i = 0; i < nr; ++i) {
- if (DRM_COPY_FROM_USER_UNCHECKED
+ if (DRM_COPY_FROM_USER
(&box, &cmdbuf->boxes[n + i], sizeof(box))) {
DRM_ERROR("copy cliprect faulted\n");
return -EFAULT;
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 6fce2eb..4e796ec 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -265,6 +265,12 @@ static int r420_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r100_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
/* 1M ring buffer */
@@ -411,10 +417,6 @@ int r420_init(struct radeon_device *rdev)
if (r) {
return r;
}
- r = radeon_irq_kms_init(rdev);
- if (r) {
- return r;
- }
/* Memory manager */
r = radeon_bo_init(rdev);
if (r) {
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index f795a4e..e1aece7 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -194,6 +194,12 @@ static int r520_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
/* 1M ring buffer */
@@ -297,9 +303,6 @@ int r520_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 1a08008..0e53416 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -1046,6 +1046,24 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev)
return -1;
}
+uint32_t rs780_mc_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+ uint32_t r;
+
+ WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg));
+ r = RREG32(R_0028FC_MC_DATA);
+ WREG32(R_0028F8_MC_INDEX, ~C_0028F8_MC_IND_ADDR);
+ return r;
+}
+
+void rs780_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+ WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg) |
+ S_0028F8_MC_IND_WR_EN(1));
+ WREG32(R_0028FC_MC_DATA, v);
+ WREG32(R_0028F8_MC_INDEX, 0x7F);
+}
+
static void r600_mc_program(struct radeon_device *rdev)
{
struct rv515_mc_save save;
@@ -1181,6 +1199,8 @@ static int r600_mc_init(struct radeon_device *rdev)
{
u32 tmp;
int chansize, numchan;
+ uint32_t h_addr, l_addr;
+ unsigned long long k8_addr;
/* Get VRAM informations */
rdev->mc.vram_is_ddr = true;
@@ -1221,7 +1241,30 @@ static int r600_mc_init(struct radeon_device *rdev)
if (rdev->flags & RADEON_IS_IGP) {
rs690_pm_info(rdev);
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
+
+ if (rdev->family == CHIP_RS780 || rdev->family == CHIP_RS880) {
+ /* Use K8 direct mapping for fast fb access. */
+ rdev->fastfb_working = false;
+ h_addr = G_000012_K8_ADDR_EXT(RREG32_MC(R_000012_MC_MISC_UMA_CNTL));
+ l_addr = RREG32_MC(R_000011_K8_FB_LOCATION);
+ k8_addr = ((unsigned long long)h_addr) << 32 | l_addr;
+#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
+ if (k8_addr + rdev->mc.visible_vram_size < 0x100000000ULL)
+#endif
+ {
+ /* FastFB shall be used with UMA memory. Here it is simply disabled when sideport
+ * memory is present.
+ */
+ if (rdev->mc.igp_sideport_enabled == false && radeon_fastfb == 1) {
+ DRM_INFO("Direct mapping: aper base at 0x%llx, replaced by direct mapping base 0x%llx.\n",
+ (unsigned long long)rdev->mc.aper_base, k8_addr);
+ rdev->mc.aper_base = (resource_size_t)k8_addr;
+ rdev->fastfb_working = true;
+ }
+ }
+ }
}
+
radeon_update_bandwidth_info(rdev);
return 0;
}
@@ -3202,6 +3245,12 @@ static int r600_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r = r600_irq_init(rdev);
if (r) {
DRM_ERROR("radeon: IH init failed (%d).\n", r);
@@ -3356,10 +3405,6 @@ int r600_init(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
-
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
@@ -4631,8 +4676,6 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev)
{
u32 link_width_cntl, lanes, speed_cntl, training_cntl, tmp;
u16 link_cntl2;
- u32 mask;
- int ret;
if (radeon_pcie_gen2 == 0)
return;
@@ -4651,11 +4694,8 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev)
if (rdev->family <= CHIP_R600)
return;
- ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask);
- if (ret != 0)
- return;
-
- if (!(mask & DRM_PCIE_SPEED_50))
+ if ((rdev->pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) &&
+ (rdev->pdev->bus->max_bus_speed != PCIE_SPEED_8_0GT))
return;
speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 47f180a..456750a 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -232,7 +232,7 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- u32 base_rate = 48000;
+ u32 base_rate = 24000;
if (!dig || !dig->afmt)
return;
@@ -240,7 +240,6 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
/* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
* doesn't matter which one you use. Just use the first one.
*/
- /* XXX: properly calculate this */
/* XXX two dtos; generally use dto0 for hdmi */
/* Express [24MHz / target pixel clock] as an exact rational
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
@@ -250,13 +249,13 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
/* according to the reg specs, this should DCE3.2 only, but in
* practice it seems to cover DCE3.0 as well.
*/
- WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 50);
+ WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
} else {
/* according to the reg specs, this should be DCE2.0 and DCE3.0 */
- WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate * 50) |
- AUDIO_DTO_MODULE(clock * 100));
+ WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate / 10) |
+ AUDIO_DTO_MODULE(clock / 10));
}
}
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index acb146c..79df558 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -1342,6 +1342,14 @@
#define PACKET3_STRMOUT_BASE_UPDATE 0x72 /* r7xx */
#define PACKET3_SURFACE_BASE_UPDATE 0x73
+#define R_000011_K8_FB_LOCATION 0x11
+#define R_000012_MC_MISC_UMA_CNTL 0x12
+#define G_000012_K8_ADDR_EXT(x) (((x) >> 0) & 0xFF)
+#define R_0028F8_MC_INDEX 0x28F8
+#define S_0028F8_MC_IND_ADDR(x) (((x) & 0x1FF) << 0)
+#define C_0028F8_MC_IND_ADDR 0xFFFFFE00
+#define S_0028F8_MC_IND_WR_EN(x) (((x) & 0x1) << 9)
+#define R_0028FC_MC_DATA 0x28FC
#define R_008020_GRBM_SOFT_RESET 0x8020
#define S_008020_SOFT_RESET_CP(x) (((x) & 1) << 0)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 1442ce7..142ce6c 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1694,6 +1694,7 @@ struct radeon_device {
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
bool audio_enabled;
+ bool has_uvd;
struct r600_audio audio_status; /* audio stuff */
struct notifier_block acpi_nb;
/* only one userspace can use Hyperz features or CMASK at a time */
@@ -1838,6 +1839,7 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
#define ASIC_IS_DCE61(rdev) ((rdev->family >= CHIP_ARUBA) && \
(rdev->flags & RADEON_IS_IGP))
#define ASIC_IS_DCE64(rdev) ((rdev->family == CHIP_OLAND))
+#define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN))
/*
* BIOS helpers.
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index 6417132..a2802b47 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -122,6 +122,10 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
rdev->mc_rreg = &rs600_mc_rreg;
rdev->mc_wreg = &rs600_mc_wreg;
}
+ if (rdev->family == CHIP_RS780 || rdev->family == CHIP_RS880) {
+ rdev->mc_rreg = &rs780_mc_rreg;
+ rdev->mc_wreg = &rs780_mc_wreg;
+ }
if (rdev->family >= CHIP_R600) {
rdev->pciep_rreg = &r600_pciep_rreg;
rdev->pciep_wreg = &r600_pciep_wreg;
@@ -1935,6 +1939,8 @@ int radeon_asic_init(struct radeon_device *rdev)
else
rdev->num_crtc = 2;
+ rdev->has_uvd = false;
+
switch (rdev->family) {
case CHIP_R100:
case CHIP_RV100:
@@ -1999,16 +2005,22 @@ int radeon_asic_init(struct radeon_device *rdev)
case CHIP_RV635:
case CHIP_RV670:
rdev->asic = &r600_asic;
+ if (rdev->family == CHIP_R600)
+ rdev->has_uvd = false;
+ else
+ rdev->has_uvd = true;
break;
case CHIP_RS780:
case CHIP_RS880:
rdev->asic = &rs780_asic;
+ rdev->has_uvd = true;
break;
case CHIP_RV770:
case CHIP_RV730:
case CHIP_RV710:
case CHIP_RV740:
rdev->asic = &rv770_asic;
+ rdev->has_uvd = true;
break;
case CHIP_CEDAR:
case CHIP_REDWOOD:
@@ -2021,11 +2033,13 @@ int radeon_asic_init(struct radeon_device *rdev)
else
rdev->num_crtc = 6;
rdev->asic = &evergreen_asic;
+ rdev->has_uvd = true;
break;
case CHIP_PALM:
case CHIP_SUMO:
case CHIP_SUMO2:
rdev->asic = &sumo_asic;
+ rdev->has_uvd = true;
break;
case CHIP_BARTS:
case CHIP_TURKS:
@@ -2036,27 +2050,37 @@ int radeon_asic_init(struct radeon_device *rdev)
else
rdev->num_crtc = 6;
rdev->asic = &btc_asic;
+ rdev->has_uvd = true;
break;
case CHIP_CAYMAN:
rdev->asic = &cayman_asic;
/* set num crtcs */
rdev->num_crtc = 6;
+ rdev->has_uvd = true;
break;
case CHIP_ARUBA:
rdev->asic = &trinity_asic;
/* set num crtcs */
rdev->num_crtc = 4;
+ rdev->has_uvd = true;
break;
case CHIP_TAHITI:
case CHIP_PITCAIRN:
case CHIP_VERDE:
case CHIP_OLAND:
+ case CHIP_HAINAN:
rdev->asic = &si_asic;
/* set num crtcs */
- if (rdev->family == CHIP_OLAND)
+ if (rdev->family == CHIP_HAINAN)
+ rdev->num_crtc = 0;
+ else if (rdev->family == CHIP_OLAND)
rdev->num_crtc = 2;
else
rdev->num_crtc = 6;
+ if (rdev->family == CHIP_HAINAN)
+ rdev->has_uvd = false;
+ else
+ rdev->has_uvd = true;
break;
default:
/* FIXME: not supported yet */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 2c87365..a72759e 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -347,6 +347,8 @@ extern bool r600_gui_idle(struct radeon_device *rdev);
extern void r600_pm_misc(struct radeon_device *rdev);
extern void r600_pm_init_profile(struct radeon_device *rdev);
extern void rs780_pm_init_profile(struct radeon_device *rdev);
+extern uint32_t rs780_mc_rreg(struct radeon_device *rdev, uint32_t reg);
+extern void rs780_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
extern void r600_pm_get_dynpm_state(struct radeon_device *rdev);
extern void r600_set_pcie_lanes(struct radeon_device *rdev, int lanes);
extern int r600_get_pcie_lanes(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index fa3c56f..061b227 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -244,24 +244,28 @@ static bool ni_read_disabled_bios(struct radeon_device *rdev)
/* enable the rom */
WREG32(R600_BUS_CNTL, (bus_cntl & ~R600_BIOS_ROM_DIS));
- /* Disable VGA mode */
- WREG32(AVIVO_D1VGA_CONTROL,
- (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
- AVIVO_DVGA_CONTROL_TIMING_SELECT)));
- WREG32(AVIVO_D2VGA_CONTROL,
- (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
- AVIVO_DVGA_CONTROL_TIMING_SELECT)));
- WREG32(AVIVO_VGA_RENDER_CONTROL,
- (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
+ if (!ASIC_IS_NODCE(rdev)) {
+ /* Disable VGA mode */
+ WREG32(AVIVO_D1VGA_CONTROL,
+ (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+ AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+ WREG32(AVIVO_D2VGA_CONTROL,
+ (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+ AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+ WREG32(AVIVO_VGA_RENDER_CONTROL,
+ (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
+ }
WREG32(R600_ROM_CNTL, rom_cntl | R600_SCK_OVERWRITE);
r = radeon_read_bios(rdev);
/* restore regs */
WREG32(R600_BUS_CNTL, bus_cntl);
- WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
- WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
- WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
+ if (!ASIC_IS_NODCE(rdev)) {
+ WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
+ WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
+ WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
+ }
WREG32(R600_ROM_CNTL, rom_cntl);
return r;
}
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index a8f6089..1899738 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -94,6 +94,7 @@ static const char radeon_family_name[][16] = {
"PITCAIRN",
"VERDE",
"OLAND",
+ "HAINAN",
"LAST",
};
@@ -466,23 +467,27 @@ bool radeon_card_posted(struct radeon_device *rdev)
{
uint32_t reg;
+ /* required for EFI mode on macbook2,1 which uses an r5xx asic */
if (efi_enabled(EFI_BOOT) &&
- rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE)
+ (rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
+ (rdev->family < CHIP_R600))
return false;
+ if (ASIC_IS_NODCE(rdev))
+ goto check_memsize;
+
/* first check CRTCs */
- if (ASIC_IS_DCE41(rdev)) {
+ if (ASIC_IS_DCE4(rdev)) {
reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
- if (reg & EVERGREEN_CRTC_MASTER_EN)
- return true;
- } else if (ASIC_IS_DCE4(rdev)) {
- reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ if (rdev->num_crtc >= 4) {
+ reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
+ }
+ if (rdev->num_crtc >= 6) {
+ reg |= RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) |
+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ }
if (reg & EVERGREEN_CRTC_MASTER_EN)
return true;
} else if (ASIC_IS_AVIVO(rdev)) {
@@ -499,6 +504,7 @@ bool radeon_card_posted(struct radeon_device *rdev)
}
}
+check_memsize:
/* then check MEM_SIZE, in case the crtcs are off */
if (rdev->family >= CHIP_R600)
reg = RREG32(R600_CONFIG_MEMSIZE);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index e38fd55..eb18bb7 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -271,8 +271,6 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
{
struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id];
struct radeon_unpin_work *work;
- struct drm_pending_vblank_event *e;
- struct timeval now;
unsigned long flags;
u32 update_pending;
int vpos, hpos;
@@ -328,14 +326,9 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
radeon_crtc->unpin_work = NULL;
/* wakeup userspace */
- if (work->event) {
- e = work->event;
- e->event.sequence = drm_vblank_count_and_time(rdev->ddev, crtc_id, &now);
- e->event.tv_sec = now.tv_sec;
- e->event.tv_usec = now.tv_usec;
- list_add_tail(&e->base.link, &e->base.file_priv->event_list);
- wake_up_interruptible(&e->base.file_priv->event_wait);
- }
+ if (work->event)
+ drm_send_vblank_event(rdev->ddev, crtc_id, work->event);
+
spin_unlock_irqrestore(&rdev->ddev->event_lock, flags);
drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index d33f484..094e7e5 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -147,7 +147,7 @@ static inline void radeon_unregister_atpx_handler(void) {}
#endif
int radeon_no_wb;
-int radeon_modeset = 1;
+int radeon_modeset = -1;
int radeon_dynclks = -1;
int radeon_r4xx_atom = 0;
int radeon_agpmode = 0;
@@ -456,6 +456,16 @@ static struct pci_driver radeon_kms_pci_driver = {
static int __init radeon_init(void)
{
+#ifdef CONFIG_VGA_CONSOLE
+ if (vgacon_text_force() && radeon_modeset == -1) {
+ DRM_INFO("VGACON disable radeon kernel modesetting.\n");
+ radeon_modeset = 0;
+ }
+#endif
+ /* set to modesetting by default if not nomodeset */
+ if (radeon_modeset == -1)
+ radeon_modeset = 1;
+
if (radeon_modeset == 1) {
DRM_INFO("radeon kernel modesetting enabled.\n");
driver = &kms_driver;
diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h
index 2d91123..36e9803 100644
--- a/drivers/gpu/drm/radeon/radeon_family.h
+++ b/drivers/gpu/drm/radeon/radeon_family.h
@@ -92,6 +92,7 @@ enum radeon_family {
CHIP_PITCAIRN,
CHIP_VERDE,
CHIP_OLAND,
+ CHIP_HAINAN,
CHIP_LAST,
};
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 6857cb4..7cb178a 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
@@ -1031,11 +1031,9 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,
static void radeon_crtc_prepare(struct drm_crtc *crtc)
{
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct drm_crtc *crtci;
- radeon_crtc->in_mode_set = true;
/*
* The hardware wedges sometimes if you reconfigure one CRTC
* whilst another is running (see fdo bug #24611).
@@ -1046,7 +1044,6 @@ static void radeon_crtc_prepare(struct drm_crtc *crtc)
static void radeon_crtc_commit(struct drm_crtc *crtc)
{
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct drm_crtc *crtci;
@@ -1057,7 +1054,6 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
if (crtci->enabled)
radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON);
}
- radeon_crtc->in_mode_set = false;
}
static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 44e579e..69ad4fe 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -302,7 +302,6 @@ struct radeon_crtc {
u16 lut_r[256], lut_g[256], lut_b[256];
bool enabled;
bool can_tile;
- bool in_mode_set;
uint32_t crtc_offset;
struct drm_gem_object *cursor_bo;
uint64_t cursor_addr;
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 93f760e..6c0ce89 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -726,7 +726,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
return r;
}
DRM_INFO("radeon: %uM of VRAM memory ready\n",
- (unsigned)rdev->mc.real_vram_size / (1024 * 1024));
+ (unsigned) (rdev->mc.real_vram_size / (1024 * 1024)));
r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT,
rdev->mc.gtt_size >> PAGE_SHIFT);
if (r) {
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index 73051ce..233a9b9 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -417,6 +417,12 @@ static int rs400_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r100_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
/* 1M ring buffer */
@@ -535,9 +541,6 @@ int rs400_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 46fa1b0..670b555 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -923,6 +923,12 @@ static int rs600_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
/* 1M ring buffer */
@@ -1047,9 +1053,6 @@ int rs600_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index ab4c86c..55880d5 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -651,6 +651,12 @@ static int rs690_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
/* 1M ring buffer */
@@ -776,9 +782,6 @@ int rs690_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index ffcba73..21c7d7b 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -532,6 +532,12 @@ static int rv515_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
rs600_irq_set(rdev);
rdev->config.r300.hdp_cntl = RREG32(RADEON_HOST_PATH_CNTL);
/* 1M ring buffer */
@@ -662,9 +668,6 @@ int rv515_init(struct radeon_device *rdev)
r = radeon_fence_driver_init(rdev);
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
/* Memory manager */
r = radeon_bo_init(rdev);
if (r)
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 83f612a..4a62ad2 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -862,10 +862,8 @@ int rv770_uvd_resume(struct radeon_device *rdev)
chip_id = 0x0100000b;
break;
case CHIP_SUMO:
- chip_id = 0x0100000c;
- break;
case CHIP_SUMO2:
- chip_id = 0x0100000d;
+ chip_id = 0x0100000c;
break;
case CHIP_PALM:
chip_id = 0x0100000e;
@@ -1889,6 +1887,12 @@ static int rv770_startup(struct radeon_device *rdev)
rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r = r600_irq_init(rdev);
if (r) {
DRM_ERROR("radeon: IH init failed (%d).\n", r);
@@ -2047,10 +2051,6 @@ int rv770_init(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
-
rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
@@ -2113,8 +2113,6 @@ static void rv770_pcie_gen2_enable(struct radeon_device *rdev)
{
u32 link_width_cntl, lanes, speed_cntl, tmp;
u16 link_cntl2;
- u32 mask;
- int ret;
if (radeon_pcie_gen2 == 0)
return;
@@ -2129,11 +2127,8 @@ static void rv770_pcie_gen2_enable(struct radeon_device *rdev)
if (ASIC_IS_X2(rdev))
return;
- ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask);
- if (ret != 0)
- return;
-
- if (!(mask & DRM_PCIE_SPEED_50))
+ if ((rdev->pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) &&
+ (rdev->pdev->bus->max_bus_speed != PCIE_SPEED_8_0GT))
return;
DRM_INFO("enabling PCIE gen 2 link speeds, disable with radeon.pcie_gen2=0\n");
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index f0b6c2f..a1b0da6 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -60,6 +60,11 @@ MODULE_FIRMWARE("radeon/OLAND_me.bin");
MODULE_FIRMWARE("radeon/OLAND_ce.bin");
MODULE_FIRMWARE("radeon/OLAND_mc.bin");
MODULE_FIRMWARE("radeon/OLAND_rlc.bin");
+MODULE_FIRMWARE("radeon/HAINAN_pfp.bin");
+MODULE_FIRMWARE("radeon/HAINAN_me.bin");
+MODULE_FIRMWARE("radeon/HAINAN_ce.bin");
+MODULE_FIRMWARE("radeon/HAINAN_mc.bin");
+MODULE_FIRMWARE("radeon/HAINAN_rlc.bin");
extern int r600_ih_ring_alloc(struct radeon_device *rdev);
extern void r600_ih_ring_fini(struct radeon_device *rdev);
@@ -265,6 +270,40 @@ static const u32 oland_golden_registers[] =
0x15c0, 0x000c0fc0, 0x000c0400
};
+static const u32 hainan_golden_registers[] =
+{
+ 0x9a10, 0x00010000, 0x00018208,
+ 0x9830, 0xffffffff, 0x00000000,
+ 0x9834, 0xf00fffff, 0x00000400,
+ 0x9838, 0x0002021c, 0x00020200,
+ 0xd0c0, 0xff000fff, 0x00000100,
+ 0xd030, 0x000300c0, 0x00800040,
+ 0xd8c0, 0xff000fff, 0x00000100,
+ 0xd830, 0x000300c0, 0x00800040,
+ 0x2ae4, 0x00073ffe, 0x000022a2,
+ 0x240c, 0x000007ff, 0x00000000,
+ 0x8a14, 0xf000001f, 0x00000007,
+ 0x8b24, 0xffffffff, 0x00ffffff,
+ 0x8b10, 0x0000ff0f, 0x00000000,
+ 0x28a4c, 0x07ffffff, 0x4e000000,
+ 0x28350, 0x3f3f3fff, 0x00000000,
+ 0x30, 0x000000ff, 0x0040,
+ 0x34, 0x00000040, 0x00004040,
+ 0x9100, 0x03e00000, 0x03600000,
+ 0x9060, 0x0000007f, 0x00000020,
+ 0x9508, 0x00010000, 0x00010000,
+ 0xac14, 0x000003ff, 0x000000f1,
+ 0xac10, 0xffffffff, 0x00000000,
+ 0xac0c, 0xffffffff, 0x00003210,
+ 0x88d4, 0x0000001f, 0x00000010,
+ 0x15c0, 0x000c0fc0, 0x000c0400
+};
+
+static const u32 hainan_golden_registers2[] =
+{
+ 0x98f8, 0xffffffff, 0x02010001
+};
+
static const u32 tahiti_mgcg_cgcg_init[] =
{
0xc400, 0xffffffff, 0xfffffffc,
@@ -673,6 +712,83 @@ static const u32 oland_mgcg_cgcg_init[] =
0xd8c0, 0xfffffff0, 0x00000100
};
+static const u32 hainan_mgcg_cgcg_init[] =
+{
+ 0xc400, 0xffffffff, 0xfffffffc,
+ 0x802c, 0xffffffff, 0xe0000000,
+ 0x9a60, 0xffffffff, 0x00000100,
+ 0x92a4, 0xffffffff, 0x00000100,
+ 0xc164, 0xffffffff, 0x00000100,
+ 0x9774, 0xffffffff, 0x00000100,
+ 0x8984, 0xffffffff, 0x06000100,
+ 0x8a18, 0xffffffff, 0x00000100,
+ 0x92a0, 0xffffffff, 0x00000100,
+ 0xc380, 0xffffffff, 0x00000100,
+ 0x8b28, 0xffffffff, 0x00000100,
+ 0x9144, 0xffffffff, 0x00000100,
+ 0x8d88, 0xffffffff, 0x00000100,
+ 0x8d8c, 0xffffffff, 0x00000100,
+ 0x9030, 0xffffffff, 0x00000100,
+ 0x9034, 0xffffffff, 0x00000100,
+ 0x9038, 0xffffffff, 0x00000100,
+ 0x903c, 0xffffffff, 0x00000100,
+ 0xad80, 0xffffffff, 0x00000100,
+ 0xac54, 0xffffffff, 0x00000100,
+ 0x897c, 0xffffffff, 0x06000100,
+ 0x9868, 0xffffffff, 0x00000100,
+ 0x9510, 0xffffffff, 0x00000100,
+ 0xaf04, 0xffffffff, 0x00000100,
+ 0xae04, 0xffffffff, 0x00000100,
+ 0x949c, 0xffffffff, 0x00000100,
+ 0x802c, 0xffffffff, 0xe0000000,
+ 0x9160, 0xffffffff, 0x00010000,
+ 0x9164, 0xffffffff, 0x00030002,
+ 0x9168, 0xffffffff, 0x00040007,
+ 0x916c, 0xffffffff, 0x00060005,
+ 0x9170, 0xffffffff, 0x00090008,
+ 0x9174, 0xffffffff, 0x00020001,
+ 0x9178, 0xffffffff, 0x00040003,
+ 0x917c, 0xffffffff, 0x00000007,
+ 0x9180, 0xffffffff, 0x00060005,
+ 0x9184, 0xffffffff, 0x00090008,
+ 0x9188, 0xffffffff, 0x00030002,
+ 0x918c, 0xffffffff, 0x00050004,
+ 0x9190, 0xffffffff, 0x00000008,
+ 0x9194, 0xffffffff, 0x00070006,
+ 0x9198, 0xffffffff, 0x000a0009,
+ 0x919c, 0xffffffff, 0x00040003,
+ 0x91a0, 0xffffffff, 0x00060005,
+ 0x91a4, 0xffffffff, 0x00000009,
+ 0x91a8, 0xffffffff, 0x00080007,
+ 0x91ac, 0xffffffff, 0x000b000a,
+ 0x91b0, 0xffffffff, 0x00050004,
+ 0x91b4, 0xffffffff, 0x00070006,
+ 0x91b8, 0xffffffff, 0x0008000b,
+ 0x91bc, 0xffffffff, 0x000a0009,
+ 0x91c0, 0xffffffff, 0x000d000c,
+ 0x91c4, 0xffffffff, 0x00060005,
+ 0x91c8, 0xffffffff, 0x00080007,
+ 0x91cc, 0xffffffff, 0x0000000b,
+ 0x91d0, 0xffffffff, 0x000a0009,
+ 0x91d4, 0xffffffff, 0x000d000c,
+ 0x9150, 0xffffffff, 0x96940200,
+ 0x8708, 0xffffffff, 0x00900100,
+ 0xc478, 0xffffffff, 0x00000080,
+ 0xc404, 0xffffffff, 0x0020003f,
+ 0x30, 0xffffffff, 0x0000001c,
+ 0x34, 0x000f0000, 0x000f0000,
+ 0x160c, 0xffffffff, 0x00000100,
+ 0x1024, 0xffffffff, 0x00000100,
+ 0x20a8, 0xffffffff, 0x00000104,
+ 0x264c, 0x000c0000, 0x000c0000,
+ 0x2648, 0x000c0000, 0x000c0000,
+ 0x2f50, 0x00000001, 0x00000001,
+ 0x30cc, 0xc0000fff, 0x00000104,
+ 0xc1e4, 0x00000001, 0x00000001,
+ 0xd0c0, 0xfffffff0, 0x00000100,
+ 0xd8c0, 0xfffffff0, 0x00000100
+};
+
static u32 verde_pg_init[] =
{
0x353c, 0xffffffff, 0x40000,
@@ -853,6 +969,17 @@ static void si_init_golden_registers(struct radeon_device *rdev)
oland_mgcg_cgcg_init,
(const u32)ARRAY_SIZE(oland_mgcg_cgcg_init));
break;
+ case CHIP_HAINAN:
+ radeon_program_register_sequence(rdev,
+ hainan_golden_registers,
+ (const u32)ARRAY_SIZE(hainan_golden_registers));
+ radeon_program_register_sequence(rdev,
+ hainan_golden_registers2,
+ (const u32)ARRAY_SIZE(hainan_golden_registers2));
+ radeon_program_register_sequence(rdev,
+ hainan_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(hainan_mgcg_cgcg_init));
+ break;
default:
break;
}
@@ -1062,6 +1189,45 @@ static const u32 oland_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = {
{0x0000009f, 0x00a17730}
};
+static const u32 hainan_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = {
+ {0x0000006f, 0x03044000},
+ {0x00000070, 0x0480c018},
+ {0x00000071, 0x00000040},
+ {0x00000072, 0x01000000},
+ {0x00000074, 0x000000ff},
+ {0x00000075, 0x00143400},
+ {0x00000076, 0x08ec0800},
+ {0x00000077, 0x040000cc},
+ {0x00000079, 0x00000000},
+ {0x0000007a, 0x21000409},
+ {0x0000007c, 0x00000000},
+ {0x0000007d, 0xe8000000},
+ {0x0000007e, 0x044408a8},
+ {0x0000007f, 0x00000003},
+ {0x00000080, 0x00000000},
+ {0x00000081, 0x01000000},
+ {0x00000082, 0x02000000},
+ {0x00000083, 0x00000000},
+ {0x00000084, 0xe3f3e4f4},
+ {0x00000085, 0x00052024},
+ {0x00000087, 0x00000000},
+ {0x00000088, 0x66036603},
+ {0x00000089, 0x01000000},
+ {0x0000008b, 0x1c0a0000},
+ {0x0000008c, 0xff010000},
+ {0x0000008e, 0xffffefff},
+ {0x0000008f, 0xfff3efff},
+ {0x00000090, 0xfff3efbf},
+ {0x00000094, 0x00101101},
+ {0x00000095, 0x00000fff},
+ {0x00000096, 0x00116fff},
+ {0x00000097, 0x60010000},
+ {0x00000098, 0x10010000},
+ {0x00000099, 0x00006000},
+ {0x0000009a, 0x00001000},
+ {0x0000009f, 0x00a07730}
+};
+
/* ucode loading */
static int si_mc_load_microcode(struct radeon_device *rdev)
{
@@ -1095,6 +1261,11 @@ static int si_mc_load_microcode(struct radeon_device *rdev)
ucode_size = OLAND_MC_UCODE_SIZE;
regs_size = TAHITI_IO_MC_REGS_SIZE;
break;
+ case CHIP_HAINAN:
+ io_mc_regs = (u32 *)&hainan_io_mc_regs;
+ ucode_size = OLAND_MC_UCODE_SIZE;
+ regs_size = TAHITI_IO_MC_REGS_SIZE;
+ break;
}
running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
@@ -1198,6 +1369,15 @@ static int si_init_microcode(struct radeon_device *rdev)
rlc_req_size = SI_RLC_UCODE_SIZE * 4;
mc_req_size = OLAND_MC_UCODE_SIZE * 4;
break;
+ case CHIP_HAINAN:
+ chip_name = "HAINAN";
+ rlc_chip_name = "HAINAN";
+ pfp_req_size = SI_PFP_UCODE_SIZE * 4;
+ me_req_size = SI_PM4_UCODE_SIZE * 4;
+ ce_req_size = SI_CE_UCODE_SIZE * 4;
+ rlc_req_size = SI_RLC_UCODE_SIZE * 4;
+ mc_req_size = OLAND_MC_UCODE_SIZE * 4;
+ break;
default: BUG();
}
@@ -2003,7 +2183,8 @@ static void si_tiling_mode_table_init(struct radeon_device *rdev)
WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
}
} else if ((rdev->family == CHIP_VERDE) ||
- (rdev->family == CHIP_OLAND)) {
+ (rdev->family == CHIP_OLAND) ||
+ (rdev->family == CHIP_HAINAN)) {
for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
switch (reg_offset) {
case 0: /* non-AA compressed depth or any compressed stencil */
@@ -2435,7 +2616,7 @@ static void si_gpu_init(struct radeon_device *rdev)
default:
rdev->config.si.max_shader_engines = 1;
rdev->config.si.max_tile_pipes = 4;
- rdev->config.si.max_cu_per_sh = 2;
+ rdev->config.si.max_cu_per_sh = 5;
rdev->config.si.max_sh_per_se = 2;
rdev->config.si.max_backends_per_se = 4;
rdev->config.si.max_texture_channel_caches = 4;
@@ -2466,6 +2647,23 @@ static void si_gpu_init(struct radeon_device *rdev)
rdev->config.si.sc_earlyz_tile_fifo_size = 0x130;
gb_addr_config = VERDE_GB_ADDR_CONFIG_GOLDEN;
break;
+ case CHIP_HAINAN:
+ rdev->config.si.max_shader_engines = 1;
+ rdev->config.si.max_tile_pipes = 4;
+ rdev->config.si.max_cu_per_sh = 5;
+ rdev->config.si.max_sh_per_se = 1;
+ rdev->config.si.max_backends_per_se = 1;
+ rdev->config.si.max_texture_channel_caches = 2;
+ rdev->config.si.max_gprs = 256;
+ rdev->config.si.max_gs_threads = 16;
+ rdev->config.si.max_hw_contexts = 8;
+
+ rdev->config.si.sc_prim_fifo_size_frontend = 0x20;
+ rdev->config.si.sc_prim_fifo_size_backend = 0x40;
+ rdev->config.si.sc_hiz_tile_fifo_size = 0x30;
+ rdev->config.si.sc_earlyz_tile_fifo_size = 0x130;
+ gb_addr_config = HAINAN_GB_ADDR_CONFIG_GOLDEN;
+ break;
}
/* Initialize HDP */
@@ -2559,9 +2757,11 @@ static void si_gpu_init(struct radeon_device *rdev)
WREG32(HDP_ADDR_CONFIG, gb_addr_config);
WREG32(DMA_TILING_CONFIG + DMA0_REGISTER_OFFSET, gb_addr_config);
WREG32(DMA_TILING_CONFIG + DMA1_REGISTER_OFFSET, gb_addr_config);
- WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config);
- WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config);
- WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config);
+ if (rdev->has_uvd) {
+ WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config);
+ WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config);
+ WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config);
+ }
si_tiling_mode_table_init(rdev);
@@ -3304,8 +3504,9 @@ static void si_mc_program(struct radeon_device *rdev)
if (radeon_mc_wait_for_idle(rdev)) {
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
- /* Lockout access through VGA aperture*/
- WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
+ if (!ASIC_IS_NODCE(rdev))
+ /* Lockout access through VGA aperture*/
+ WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
/* Update configuration */
WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
rdev->mc.vram_start >> 12);
@@ -3327,9 +3528,11 @@ static void si_mc_program(struct radeon_device *rdev)
dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
evergreen_mc_resume(rdev, &save);
- /* we need to own VRAM, so turn off the VGA renderer here
- * to stop it overwriting our objects */
- rv515_vga_render_disable(rdev);
+ if (!ASIC_IS_NODCE(rdev)) {
+ /* we need to own VRAM, so turn off the VGA renderer here
+ * to stop it overwriting our objects */
+ rv515_vga_render_disable(rdev);
+ }
}
static void si_vram_gtt_location(struct radeon_device *rdev,
@@ -3397,8 +3600,8 @@ static int si_mc_init(struct radeon_device *rdev)
rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
/* size in MB on si */
- rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
- rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
+ rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024ULL * 1024ULL;
rdev->mc.visible_vram_size = rdev->mc.aper_size;
si_vram_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
@@ -4251,8 +4454,10 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
tmp = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, tmp);
WREG32(GRBM_INT_CNTL, 0);
- WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
- WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+ if (rdev->num_crtc >= 2) {
+ WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+ WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+ }
if (rdev->num_crtc >= 4) {
WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
@@ -4262,8 +4467,10 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
}
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+ if (rdev->num_crtc >= 2) {
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+ }
if (rdev->num_crtc >= 4) {
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
@@ -4273,21 +4480,22 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
}
- WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
-
- tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
- WREG32(DC_HPD1_INT_CONTROL, tmp);
- tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
- WREG32(DC_HPD2_INT_CONTROL, tmp);
- tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
- WREG32(DC_HPD3_INT_CONTROL, tmp);
- tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
- WREG32(DC_HPD4_INT_CONTROL, tmp);
- tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
- WREG32(DC_HPD5_INT_CONTROL, tmp);
- tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
- WREG32(DC_HPD6_INT_CONTROL, tmp);
+ if (!ASIC_IS_NODCE(rdev)) {
+ WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
+ tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD1_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD2_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD3_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD4_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD5_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD6_INT_CONTROL, tmp);
+ }
}
static int si_irq_init(struct radeon_device *rdev)
@@ -4366,7 +4574,7 @@ int si_irq_set(struct radeon_device *rdev)
u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE;
u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0;
u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
- u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
+ u32 hpd1 = 0, hpd2 = 0, hpd3 = 0, hpd4 = 0, hpd5 = 0, hpd6 = 0;
u32 grbm_int_cntl = 0;
u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
u32 dma_cntl, dma_cntl1;
@@ -4383,12 +4591,14 @@ int si_irq_set(struct radeon_device *rdev)
return 0;
}
- hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
- hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
- hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
- hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
- hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
- hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ if (!ASIC_IS_NODCE(rdev)) {
+ hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ }
dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
dma_cntl1 = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
@@ -4479,8 +4689,10 @@ int si_irq_set(struct radeon_device *rdev)
WREG32(GRBM_INT_CNTL, grbm_int_cntl);
- WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
- WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
+ if (rdev->num_crtc >= 2) {
+ WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
+ WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
+ }
if (rdev->num_crtc >= 4) {
WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
@@ -4490,8 +4702,10 @@ int si_irq_set(struct radeon_device *rdev)
WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
}
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1);
- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2);
+ if (rdev->num_crtc >= 2) {
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1);
+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2);
+ }
if (rdev->num_crtc >= 4) {
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3);
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4);
@@ -4501,12 +4715,14 @@ int si_irq_set(struct radeon_device *rdev)
WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6);
}
- WREG32(DC_HPD1_INT_CONTROL, hpd1);
- WREG32(DC_HPD2_INT_CONTROL, hpd2);
- WREG32(DC_HPD3_INT_CONTROL, hpd3);
- WREG32(DC_HPD4_INT_CONTROL, hpd4);
- WREG32(DC_HPD5_INT_CONTROL, hpd5);
- WREG32(DC_HPD6_INT_CONTROL, hpd6);
+ if (!ASIC_IS_NODCE(rdev)) {
+ WREG32(DC_HPD1_INT_CONTROL, hpd1);
+ WREG32(DC_HPD2_INT_CONTROL, hpd2);
+ WREG32(DC_HPD3_INT_CONTROL, hpd3);
+ WREG32(DC_HPD4_INT_CONTROL, hpd4);
+ WREG32(DC_HPD5_INT_CONTROL, hpd5);
+ WREG32(DC_HPD6_INT_CONTROL, hpd6);
+ }
return 0;
}
@@ -4515,6 +4731,9 @@ static inline void si_irq_ack(struct radeon_device *rdev)
{
u32 tmp;
+ if (ASIC_IS_NODCE(rdev))
+ return;
+
rdev->irq.stat_regs.evergreen.disp_int = RREG32(DISP_INTERRUPT_STATUS);
rdev->irq.stat_regs.evergreen.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
rdev->irq.stat_regs.evergreen.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
@@ -5118,17 +5337,25 @@ static int si_startup(struct radeon_device *rdev)
return r;
}
- r = rv770_uvd_resume(rdev);
- if (!r) {
- r = radeon_fence_driver_start_ring(rdev,
- R600_RING_TYPE_UVD_INDEX);
+ if (rdev->has_uvd) {
+ r = rv770_uvd_resume(rdev);
+ if (!r) {
+ r = radeon_fence_driver_start_ring(rdev,
+ R600_RING_TYPE_UVD_INDEX);
+ if (r)
+ dev_err(rdev->dev, "UVD fences init error (%d).\n", r);
+ }
if (r)
- dev_err(rdev->dev, "UVD fences init error (%d).\n", r);
+ rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
}
- if (r)
- rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
/* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
r = si_irq_init(rdev);
if (r) {
DRM_ERROR("radeon: IH init failed (%d).\n", r);
@@ -5185,16 +5412,18 @@ static int si_startup(struct radeon_device *rdev)
if (r)
return r;
- ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
- if (ring->ring_size) {
- r = radeon_ring_init(rdev, ring, ring->ring_size,
- R600_WB_UVD_RPTR_OFFSET,
- UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
- 0, 0xfffff, RADEON_CP_PACKET2);
- if (!r)
- r = r600_uvd_init(rdev);
- if (r)
- DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
+ if (rdev->has_uvd) {
+ ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+ if (ring->ring_size) {
+ r = radeon_ring_init(rdev, ring, ring->ring_size,
+ R600_WB_UVD_RPTR_OFFSET,
+ UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
+ 0, 0xfffff, RADEON_CP_PACKET2);
+ if (!r)
+ r = r600_uvd_init(rdev);
+ if (r)
+ DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
+ }
}
r = radeon_ib_pool_init(rdev);
@@ -5243,8 +5472,10 @@ int si_suspend(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
si_cp_enable(rdev, false);
cayman_dma_stop(rdev);
- r600_uvd_rbc_stop(rdev);
- radeon_uvd_suspend(rdev);
+ if (rdev->has_uvd) {
+ r600_uvd_rbc_stop(rdev);
+ radeon_uvd_suspend(rdev);
+ }
si_irq_suspend(rdev);
radeon_wb_disable(rdev);
si_pcie_gart_disable(rdev);
@@ -5308,10 +5539,6 @@ int si_init(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_irq_kms_init(rdev);
- if (r)
- return r;
-
ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 1024 * 1024);
@@ -5332,11 +5559,13 @@ int si_init(struct radeon_device *rdev)
ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 64 * 1024);
- r = radeon_uvd_init(rdev);
- if (!r) {
- ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
- ring->ring_obj = NULL;
- r600_ring_init(rdev, ring, 4096);
+ if (rdev->has_uvd) {
+ r = radeon_uvd_init(rdev);
+ if (!r) {
+ ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+ ring->ring_obj = NULL;
+ r600_ring_init(rdev, ring, 4096);
+ }
}
rdev->ih.ring_obj = NULL;
@@ -5384,7 +5613,8 @@ void si_fini(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
- radeon_uvd_fini(rdev);
+ if (rdev->has_uvd)
+ radeon_uvd_fini(rdev);
si_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
index 222877b..8f2d7d4 100644
--- a/drivers/gpu/drm/radeon/sid.h
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -28,6 +28,7 @@
#define TAHITI_GB_ADDR_CONFIG_GOLDEN 0x12011003
#define VERDE_GB_ADDR_CONFIG_GOLDEN 0x12010002
+#define HAINAN_GB_ADDR_CONFIG_GOLDEN 0x02010001
/* discrete uvd clocks */
#define CG_UPLL_FUNC_CNTL 0x634
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
index 7dff49e..99e2034 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c
@@ -451,27 +451,16 @@ void shmob_drm_crtc_finish_page_flip(struct shmob_drm_crtc *scrtc)
{
struct drm_pending_vblank_event *event;
struct drm_device *dev = scrtc->crtc.dev;
- struct timeval vblanktime;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
event = scrtc->event;
scrtc->event = NULL;
+ if (event) {
+ drm_send_vblank_event(dev, 0, event);
+ drm_vblank_put(dev, 0);
+ }
spin_unlock_irqrestore(&dev->event_lock, flags);
-
- if (event == NULL)
- return;
-
- event->event.sequence = drm_vblank_count_and_time(dev, 0, &vblanktime);
- event->event.tv_sec = vblanktime.tv_sec;
- event->event.tv_usec = vblanktime.tv_usec;
-
- spin_lock_irqsave(&dev->event_lock, flags);
- list_add_tail(&event->base.link, &event->base.file_priv->event_list);
- wake_up_interruptible(&event->base.file_priv->event_wait);
- spin_unlock_irqrestore(&dev->event_lock, flags);
-
- drm_vblank_put(dev, 0);
}
static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig
index e461e99..7a4d101 100644
--- a/drivers/gpu/drm/tilcdc/Kconfig
+++ b/drivers/gpu/drm/tilcdc/Kconfig
@@ -6,6 +6,7 @@ config DRM_TILCDC
select DRM_GEM_CMA_HELPER
select VIDEOMODE_HELPERS
select BACKLIGHT_CLASS_DEVICE
+ select BACKLIGHT_LCD_SUPPORT
help
Choose this option if you have an TI SoC with LCDC display
controller, for example AM33xx in beagle-bone, DA8xx, or
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c
index 1e20603..8c04943 100644
--- a/drivers/gpu/host1x/drm/dc.c
+++ b/drivers/gpu/host1x/drm/dc.c
@@ -1128,11 +1128,6 @@ static int tegra_dc_probe(struct platform_device *pdev)
return err;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- dev_err(&pdev->dev, "failed to get registers\n");
- return -ENXIO;
- }
-
dc->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(dc->regs))
return PTR_ERR(dc->regs);
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index dc3ae5c..d39a5ce 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -264,9 +264,12 @@ static struct mt_class mt_classes[] = {
static void mt_free_input_name(struct hid_input *hi)
{
struct hid_device *hdev = hi->report->device;
+ const char *name = hi->input->name;
- if (hi->input->name != hdev->name)
- kfree(hi->input->name);
+ if (name != hdev->name) {
+ hi->input->name = hdev->name;
+ kfree(name);
+ }
}
static ssize_t mt_show_quirks(struct device *dev,
@@ -1040,11 +1043,11 @@ static void mt_remove(struct hid_device *hdev)
struct hid_input *hi;
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
- hid_hw_stop(hdev);
-
list_for_each_entry(hi, &hdev->inputs, list)
mt_free_input_name(hi);
+ hid_hw_stop(hdev);
+
kfree(td);
hid_set_drvdata(hdev, NULL);
}
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index bad8128..21ef689 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -329,7 +329,7 @@ static u32 get_vp_index(uuid_le *type_guid)
return 0;
}
cur_cpu = (++next_vp % max_cpus);
- return cur_cpu;
+ return hv_context.vp_index[cur_cpu];
}
/*
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index df0b699..2ebd6ce 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -1414,14 +1414,18 @@ static int abituguru_probe(struct platform_device *pdev)
pr_info("found Abit uGuru\n");
/* Register sysfs hooks */
- for (i = 0; i < sysfs_attr_i; i++)
- if (device_create_file(&pdev->dev,
- &data->sysfs_attr[i].dev_attr))
+ for (i = 0; i < sysfs_attr_i; i++) {
+ res = device_create_file(&pdev->dev,
+ &data->sysfs_attr[i].dev_attr);
+ if (res)
goto abituguru_probe_error;
- for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
- if (device_create_file(&pdev->dev,
- &abituguru_sysfs_attr[i].dev_attr))
+ }
+ for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) {
+ res = device_create_file(&pdev->dev,
+ &abituguru_sysfs_attr[i].dev_attr);
+ if (res)
goto abituguru_probe_error;
+ }
data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (!IS_ERR(data->hwmon_dev))
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index 7e76922..f920619 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -331,26 +331,68 @@ static int adm1021_detect(struct i2c_client *client,
man_id = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID);
dev_id = i2c_smbus_read_byte_data(client, ADM1021_REG_DEV_ID);
+ if (man_id < 0 || dev_id < 0)
+ return -ENODEV;
+
if (man_id == 0x4d && dev_id == 0x01)
type_name = "max1617a";
else if (man_id == 0x41) {
if ((dev_id & 0xF0) == 0x30)
type_name = "adm1023";
- else
+ else if ((dev_id & 0xF0) == 0x00)
type_name = "adm1021";
+ else
+ return -ENODEV;
} else if (man_id == 0x49)
type_name = "thmc10";
else if (man_id == 0x23)
type_name = "gl523sm";
else if (man_id == 0x54)
type_name = "mc1066";
- /* LM84 Mfr ID in a different place, and it has more unused bits */
- else if (conv_rate == 0x00
- && (config & 0x7F) == 0x00
- && (status & 0xAB) == 0x00)
- type_name = "lm84";
- else
- type_name = "max1617";
+ else {
+ int lte, rte, lhi, rhi, llo, rlo;
+
+ /* extra checks for LM84 and MAX1617 to avoid misdetections */
+
+ llo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(0));
+ rlo = i2c_smbus_read_byte_data(client, ADM1021_REG_THYST_R(1));
+
+ /* fail if any of the additional register reads failed */
+ if (llo < 0 || rlo < 0)
+ return -ENODEV;
+
+ lte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(0));
+ rte = i2c_smbus_read_byte_data(client, ADM1021_REG_TEMP(1));
+ lhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(0));
+ rhi = i2c_smbus_read_byte_data(client, ADM1021_REG_TOS_R(1));
+
+ /*
+ * Fail for negative temperatures and negative high limits.
+ * This check also catches read errors on the tested registers.
+ */
+ if ((s8)lte < 0 || (s8)rte < 0 || (s8)lhi < 0 || (s8)rhi < 0)
+ return -ENODEV;
+
+ /* fail if all registers hold the same value */
+ if (lte == rte && lte == lhi && lte == rhi && lte == llo
+ && lte == rlo)
+ return -ENODEV;
+
+ /*
+ * LM84 Mfr ID is in a different place,
+ * and it has more unused bits.
+ */
+ if (conv_rate == 0x00
+ && (config & 0x7F) == 0x00
+ && (status & 0xAB) == 0x00) {
+ type_name = "lm84";
+ } else {
+ /* fail if low limits are larger than high limits */
+ if ((s8)llo > lhi || (s8)rlo > rhi)
+ return -ENODEV;
+ type_name = "max1617";
+ }
+ }
pr_debug("Detected chip %s at adapter %d, address 0x%02x.\n",
type_name, i2c_adapter_id(adapter), client->addr);
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index aafa453..52b77af 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -84,8 +84,10 @@ static int iio_hwmon_probe(struct platform_device *pdev)
return PTR_ERR(channels);
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
- if (st == NULL)
- return -ENOMEM;
+ if (st == NULL) {
+ ret = -ENOMEM;
+ goto error_release_channels;
+ }
st->channels = channels;
@@ -159,7 +161,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
error_remove_group:
sysfs_remove_group(&dev->kobj, &st->attr_group);
error_release_channels:
- iio_channel_release_all(st->channels);
+ iio_channel_release_all(channels);
return ret;
}
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index f43f5e5..04638ae 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -3705,8 +3705,10 @@ static int nct6775_probe(struct platform_device *pdev)
data->have_temp |= 1 << i;
data->have_temp_fixed |= 1 << i;
data->reg_temp[0][i] = reg_temp_alternate[i];
- data->reg_temp[1][i] = reg_temp_over[i];
- data->reg_temp[2][i] = reg_temp_hyst[i];
+ if (i < num_reg_temp) {
+ data->reg_temp[1][i] = reg_temp_over[i];
+ data->reg_temp[2][i] = reg_temp_hyst[i];
+ }
data->temp_src[i] = i + 1;
continue;
}
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
index a478454..dfe6d95 100644
--- a/drivers/hwmon/tmp401.c
+++ b/drivers/hwmon/tmp401.c
@@ -240,7 +240,7 @@ static struct tmp401_data *tmp401_update_device(struct device *dev)
mutex_lock(&data->update_lock);
next_update = data->last_updated +
- msecs_to_jiffies(data->update_interval) + 1;
+ msecs_to_jiffies(data->update_interval);
if (time_after(jiffies, next_update) || !data->valid) {
if (data->kind != tmp432) {
/*
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 21fbb34..c41ca63 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -383,7 +383,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
/* Enable the adapter */
__i2c_dw_enable(dev, true);
- /* Enable interrupts */
+ /* Clear and enable interrupts */
+ i2c_dw_clear_int(dev);
dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
}
@@ -448,8 +449,14 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
cmd |= BIT(9);
if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+
+ /* avoid rx buffer overrun */
+ if (rx_limit - dev->rx_outstanding <= 0)
+ break;
+
dw_writel(dev, cmd | 0x100, DW_IC_DATA_CMD);
rx_limit--;
+ dev->rx_outstanding++;
} else
dw_writel(dev, cmd | *buf++, DW_IC_DATA_CMD);
tx_limit--; buf_len--;
@@ -502,8 +509,10 @@ i2c_dw_read(struct dw_i2c_dev *dev)
rx_valid = dw_readl(dev, DW_IC_RXFLR);
- for (; len > 0 && rx_valid > 0; len--, rx_valid--)
+ for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
*buf++ = dw_readl(dev, DW_IC_DATA_CMD);
+ dev->rx_outstanding--;
+ }
if (len > 0) {
dev->status |= STATUS_READ_IN_PROGRESS;
@@ -561,6 +570,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
dev->msg_err = 0;
dev->status = STATUS_IDLE;
dev->abort_source = 0;
+ dev->rx_outstanding = 0;
ret = i2c_dw_wait_bus_not_busy(dev);
if (ret < 0)
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 9c1840e..e761ad1 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -60,6 +60,7 @@
* @adapter: i2c subsystem adapter node
* @tx_fifo_depth: depth of the hardware tx fifo
* @rx_fifo_depth: depth of the hardware rx fifo
+ * @rx_outstanding: current master-rx elements in tx fifo
*/
struct dw_i2c_dev {
struct device *dev;
@@ -88,6 +89,7 @@ struct dw_i2c_dev {
u32 master_cfg;
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
+ int rx_outstanding;
};
#define ACCESS_SWAP 0x00000001
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 8ec9133..35b70a1 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -69,6 +69,7 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C2", 0 },
{ "INT33C3", 0 },
+ { "80860F41", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index e1cf2e0..3a6903f 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -231,7 +231,11 @@ static const char *i801_feature_names[] = {
static unsigned int disable_features;
module_param(disable_features, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(disable_features, "Disable selected driver features");
+MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n"
+ "\t\t 0x01 disable SMBus PEC\n"
+ "\t\t 0x02 disable the block buffer\n"
+ "\t\t 0x08 disable the I2C block read functionality\n"
+ "\t\t 0x10 don't use interrupts ");
/* Make sure the SMBus host is ready to start transmitting.
Return 0 if it is, -EBUSY if it is not. */
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 3bbd65d..1a3abd6 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -252,7 +252,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
writel(drv_data->cntl_bits,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->block = 0;
- wake_up_interruptible(&drv_data->waitq);
+ wake_up(&drv_data->waitq);
break;
case MV64XXX_I2C_ACTION_CONTINUE:
@@ -300,7 +300,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->block = 0;
- wake_up_interruptible(&drv_data->waitq);
+ wake_up(&drv_data->waitq);
break;
case MV64XXX_I2C_ACTION_INVALID:
@@ -315,7 +315,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
drv_data->block = 0;
- wake_up_interruptible(&drv_data->waitq);
+ wake_up(&drv_data->waitq);
break;
}
}
@@ -381,7 +381,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
unsigned long flags;
char abort = 0;
- time_left = wait_event_interruptible_timeout(drv_data->waitq,
+ time_left = wait_event_timeout(drv_data->waitq,
!drv_data->block, drv_data->adapter.timeout);
spin_lock_irqsave(&drv_data->lock, flags);
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 6e8ee92..cab1c91 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -1082,11 +1082,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
/* map the registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "cannot find IO resource\n");
- return -ENOENT;
- }
-
i2c->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->regs))
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 5a7ad24..a63c7d5 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -303,12 +303,6 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
adap->class = I2C_CLASS_HWMON;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mem_res == NULL) {
- dev_err(&pdev->dev, "Unable to get MEM resource\n");
- err = -EINVAL;
- goto out;
- }
-
siic->base = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(siic->base)) {
err = PTR_ERR(siic->base);
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index b60ff90..9aa1b60 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -714,11 +714,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "no mem resource\n");
- return -EINVAL;
- }
-
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 6b63cc7..48e31ed 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -892,7 +892,8 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
}
static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
-static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device);
+static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
+ i2c_sysfs_delete_device);
static struct attribute *i2c_adapter_attrs[] = {
&dev_attr_name.attr,
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 9f3a8ef..b3d03d3 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -390,8 +390,8 @@ static int exynos_adc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int exynos_adc_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct exynos_adc *info = platform_get_drvdata(pdev);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct exynos_adc *info = iio_priv(indio_dev);
u32 con;
if (info->version == ADC_V2) {
@@ -413,8 +413,8 @@ static int exynos_adc_suspend(struct device *dev)
static int exynos_adc_resume(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct exynos_adc *info = platform_get_drvdata(pdev);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct exynos_adc *info = iio_priv(indio_dev);
int ret;
ret = regulator_enable(info->vdd);
diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c
index 9201022..9d19ba7 100644
--- a/drivers/iio/buffer_cb.c
+++ b/drivers/iio/buffer_cb.c
@@ -64,7 +64,7 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
while (chan->indio_dev) {
if (chan->indio_dev != indio_dev) {
ret = -EINVAL;
- goto error_release_channels;
+ goto error_free_scan_mask;
}
set_bit(chan->channel->scan_index,
cb_buff->buffer.scan_mask);
@@ -73,6 +73,8 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
return cb_buff;
+error_free_scan_mask:
+ kfree(cb_buff->buffer.scan_mask);
error_release_channels:
iio_channel_release_all(cb_buff->channels);
error_free_cb_buff:
@@ -100,6 +102,7 @@ EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb);
void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buff)
{
+ kfree(cb_buff->buffer.scan_mask);
iio_channel_release_all(cb_buff->channels);
kfree(cb_buff);
}
diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
index bd33473..ed9bc8a 100644
--- a/drivers/iio/common/st_sensors/st_sensors_core.c
+++ b/drivers/iio/common/st_sensors/st_sensors_core.c
@@ -312,6 +312,8 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,
goto read_error;
*val = *val >> ch->scan_type.shift;
+
+ err = st_sensors_set_enable(indio_dev, false);
}
mutex_unlock(&indio_dev->mlock);
diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index f4a6f08..b61160b 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -5,7 +5,7 @@ menu "Digital to analog converters"
config AD5064
tristate "Analog Devices AD5064 and similar multi-channel DAC driver"
- depends on (SPI_MASTER || I2C)
+ depends on (SPI_MASTER && I2C!=m) || I2C
help
Say yes here to build support for Analog Devices AD5024, AD5025, AD5044,
AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5629R, AD5648, AD5666, AD5668,
@@ -27,7 +27,7 @@ config AD5360
config AD5380
tristate "Analog Devices AD5380/81/82/83/84/90/91/92 DAC driver"
- depends on (SPI_MASTER || I2C)
+ depends on (SPI_MASTER && I2C!=m) || I2C
select REGMAP_I2C if I2C
select REGMAP_SPI if SPI_MASTER
help
@@ -57,7 +57,7 @@ config AD5624R_SPI
config AD5446
tristate "Analog Devices AD5446 and similar single channel DACs driver"
- depends on (SPI_MASTER || I2C)
+ depends on (SPI_MASTER && I2C!=m) || I2C
help
Say yes here to build support for Analog Devices AD5300, AD5301, AD5310,
AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453,
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index a884252..e76d4ac 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -212,7 +212,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
(pdata->r2_user_settings & (ADF4350_REG2_PD_POLARITY_POS |
ADF4350_REG2_LDP_6ns | ADF4350_REG2_LDF_INT_N |
ADF4350_REG2_CHARGE_PUMP_CURR_uA(5000) |
- ADF4350_REG2_MUXOUT(0x7) | ADF4350_REG2_NOISE_MODE(0x9)));
+ ADF4350_REG2_MUXOUT(0x7) | ADF4350_REG2_NOISE_MODE(0x3)));
st->regs[ADF4350_REG3] = pdata->r3_user_settings &
(ADF4350_REG3_12BIT_CLKDIV(0xFFF) |
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 795d100..98ddc32 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -124,7 +124,7 @@ static int __of_iio_channel_get(struct iio_channel *channel,
channel->indio_dev = indio_dev;
index = iiospec.args_count ? iiospec.args[0] : 0;
if (index >= indio_dev->num_channels) {
- return -EINVAL;
+ err = -EINVAL;
goto err_put;
}
channel->channel = &indio_dev->channels[index];
@@ -450,7 +450,7 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
s64 raw64 = raw;
int ret;
- ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_SCALE);
+ ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_OFFSET);
if (ret == 0)
raw64 += offset;
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 71c2c711..34fbc2f 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -3269,9 +3269,9 @@ static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id
}
static int cma_netdev_callback(struct notifier_block *self, unsigned long event,
- void *ctx)
+ void *ptr)
{
- struct net_device *ndev = (struct net_device *)ctx;
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
struct cma_device *cma_dev;
struct rdma_id_private *id_priv;
int ret = NOTIFY_DONE;
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 23d7343..a188d31 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -1161,7 +1161,7 @@ static void netdev_removed(struct mlx4_ib_dev *dev, int port)
static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct mlx4_ib_dev *ibdev;
struct net_device *oldnd;
struct mlx4_ib_iboe *iboe;
diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c
index 81c7b73..3b9afcc 100644
--- a/drivers/infiniband/hw/qib/qib_keys.c
+++ b/drivers/infiniband/hw/qib/qib_keys.c
@@ -61,7 +61,7 @@ int qib_alloc_lkey(struct qib_mregion *mr, int dma_region)
if (dma_region) {
struct qib_mregion *tmr;
- tmr = rcu_dereference(dev->dma_mr);
+ tmr = rcu_access_pointer(dev->dma_mr);
if (!tmr) {
qib_get_mr(mr);
rcu_assign_pointer(dev->dma_mr, mr);
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index f19b099..2e84ef8 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -5,6 +5,7 @@
* Copyright (C) 2004 Alex Aizman
* Copyright (C) 2005 Mike Christie
* Copyright (c) 2005, 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
* maintained by openib-general@openib.org
*
* This software is available to you under a choice of one of two
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 06f578c..4f069c0 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -8,6 +8,7 @@
*
* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
+ * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index a00ccd1..b6d81a8 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 68ebb7f..7827baf 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 5278916..2c4941d 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
+ * Copyright (c) 2013 Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -292,10 +293,10 @@ out_err:
}
/**
- * releases the FMR pool, QP and CMA ID objects, returns 0 on success,
+ * releases the FMR pool and QP objects, returns 0 on success,
* -1 on failure
*/
-static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id)
+static int iser_free_ib_conn_res(struct iser_conn *ib_conn)
{
int cq_index;
BUG_ON(ib_conn == NULL);
@@ -314,13 +315,9 @@ static int iser_free_ib_conn_res(struct iser_conn *ib_conn, int can_destroy_id)
rdma_destroy_qp(ib_conn->cma_id);
}
- /* if cma handler context, the caller acts s.t the cma destroy the id */
- if (ib_conn->cma_id != NULL && can_destroy_id)
- rdma_destroy_id(ib_conn->cma_id);
ib_conn->fmr_pool = NULL;
ib_conn->qp = NULL;
- ib_conn->cma_id = NULL;
kfree(ib_conn->page_vec);
if (ib_conn->login_buf) {
@@ -415,11 +412,16 @@ static void iser_conn_release(struct iser_conn *ib_conn, int can_destroy_id)
list_del(&ib_conn->conn_list);
mutex_unlock(&ig.connlist_mutex);
iser_free_rx_descriptors(ib_conn);
- iser_free_ib_conn_res(ib_conn, can_destroy_id);
+ iser_free_ib_conn_res(ib_conn);
ib_conn->device = NULL;
/* on EVENT_ADDR_ERROR there's no device yet for this conn */
if (device != NULL)
iser_device_try_release(device);
+ /* if cma handler context, the caller actually destroy the id */
+ if (ib_conn->cma_id != NULL && can_destroy_id) {
+ rdma_destroy_id(ib_conn->cma_id);
+ ib_conn->cma_id = NULL;
+ }
iscsi_destroy_endpoint(ib_conn->ep);
}
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index b08ca7a..3f3f041 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -2227,6 +2227,27 @@ static void srpt_close_ch(struct srpt_rdma_ch *ch)
}
/**
+ * srpt_shutdown_session() - Whether or not a session may be shut down.
+ */
+static int srpt_shutdown_session(struct se_session *se_sess)
+{
+ struct srpt_rdma_ch *ch = se_sess->fabric_sess_ptr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ch->spinlock, flags);
+ if (ch->in_shutdown) {
+ spin_unlock_irqrestore(&ch->spinlock, flags);
+ return true;
+ }
+
+ ch->in_shutdown = true;
+ target_sess_cmd_list_set_waiting(se_sess);
+ spin_unlock_irqrestore(&ch->spinlock, flags);
+
+ return true;
+}
+
+/**
* srpt_drain_channel() - Drain a channel by resetting the IB queue pair.
* @cm_id: Pointer to the CM ID of the channel to be drained.
*
@@ -2264,6 +2285,9 @@ static void srpt_drain_channel(struct ib_cm_id *cm_id)
spin_unlock_irq(&sdev->spinlock);
if (do_reset) {
+ if (ch->sess)
+ srpt_shutdown_session(ch->sess);
+
ret = srpt_ch_qp_err(ch);
if (ret < 0)
printk(KERN_ERR "Setting queue pair in error state"
@@ -2328,7 +2352,7 @@ static void srpt_release_channel_work(struct work_struct *w)
se_sess = ch->sess;
BUG_ON(!se_sess);
- target_wait_for_sess_cmds(se_sess, 0);
+ target_wait_for_sess_cmds(se_sess);
transport_deregister_session_configfs(se_sess);
transport_deregister_session(se_sess);
@@ -3467,14 +3491,6 @@ static void srpt_release_cmd(struct se_cmd *se_cmd)
}
/**
- * srpt_shutdown_session() - Whether or not a session may be shut down.
- */
-static int srpt_shutdown_session(struct se_session *se_sess)
-{
- return true;
-}
-
-/**
* srpt_close_session() - Forcibly close a session.
*
* Callback function invoked by the TCM core to clean up sessions associated
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h
index 4caf55c..3dae156 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.h
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.h
@@ -325,6 +325,7 @@ struct srpt_rdma_ch {
u8 sess_name[36];
struct work_struct release_work;
struct completion *release_done;
+ bool in_shutdown;
};
/**
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 2f78538..b2420ae 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -1379,6 +1379,7 @@ static int synaptics_reconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
struct synaptics_data old_priv = *priv;
+ unsigned char param[2];
int retry = 0;
int error;
@@ -1394,6 +1395,7 @@ static int synaptics_reconnect(struct psmouse *psmouse)
*/
ssleep(1);
}
+ ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID);
error = synaptics_detect(psmouse, 0);
} while (error && ++retry < 3);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 0bfd8cf..518282d 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -342,10 +342,10 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
wacom->id[idx] = (data[2] << 4) | (data[3] >> 4) |
((data[7] & 0x0f) << 20) | ((data[8] & 0xf0) << 12);
- switch (wacom->id[idx] & 0xfffff) {
+ switch (wacom->id[idx]) {
case 0x812: /* Inking pen */
case 0x801: /* Intuos3 Inking pen */
- case 0x20802: /* Intuos4 Inking Pen */
+ case 0x120802: /* Intuos4/5 Inking Pen */
case 0x012:
wacom->tool[idx] = BTN_TOOL_PENCIL;
break;
@@ -356,11 +356,13 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
case 0x823: /* Intuos3 Grip Pen */
case 0x813: /* Intuos3 Classic Pen */
case 0x885: /* Intuos3 Marker Pen */
- case 0x802: /* Intuos4 General Pen */
- case 0x804: /* Intuos4 Marker Pen */
- case 0x40802: /* Intuos4 Classic Pen */
- case 0x18802: /* DTH2242 Grip Pen */
+ case 0x802: /* Intuos4/5 13HD/24HD General Pen */
+ case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */
case 0x022:
+ case 0x100804: /* Intuos4/5 13HD/24HD Art Pen */
+ case 0x140802: /* Intuos4/5 13HD/24HD Classic Pen */
+ case 0x160802: /* Cintiq 13HD Pro Pen */
+ case 0x180802: /* DTH2242 Pen */
wacom->tool[idx] = BTN_TOOL_PEN;
break;
@@ -391,10 +393,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
case 0x82b: /* Intuos3 Grip Pen Eraser */
case 0x81b: /* Intuos3 Classic Pen Eraser */
case 0x91b: /* Intuos3 Airbrush Eraser */
- case 0x80c: /* Intuos4 Marker Pen Eraser */
- case 0x80a: /* Intuos4 General Pen Eraser */
- case 0x4080a: /* Intuos4 Classic Pen Eraser */
- case 0x90a: /* Intuos4 Airbrush Eraser */
+ case 0x80c: /* Intuos4/5 13HD/24HD Marker Pen Eraser */
+ case 0x80a: /* Intuos4/5 13HD/24HD General Pen Eraser */
+ case 0x90a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+ case 0x14080a: /* Intuos4/5 13HD/24HD Classic Pen Eraser */
+ case 0x10090a: /* Intuos4/5 13HD/24HD Airbrush Eraser */
+ case 0x10080c: /* Intuos4/5 13HD/24HD Art Pen Eraser */
+ case 0x16080a: /* Cintiq 13HD Pro Pen Eraser */
+ case 0x18080a: /* DTH2242 Eraser */
wacom->tool[idx] = BTN_TOOL_RUBBER;
break;
@@ -402,7 +408,8 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
case 0x912:
case 0x112:
case 0x913: /* Intuos3 Airbrush */
- case 0x902: /* Intuos4 Airbrush */
+ case 0x902: /* Intuos4/5 13HD/24HD Airbrush */
+ case 0x100902: /* Intuos4/5 13HD/24HD Airbrush */
wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
break;
@@ -533,10 +540,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_key(input, BTN_8, (data[3] & 0x80));
}
if (data[1] | (data[2] & 0x01) | data[3]) {
- input_report_key(input, wacom->tool[1], 1);
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
} else {
- input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
} else if (features->type == DTK) {
@@ -546,6 +551,26 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_key(input, BTN_3, (data[6] & 0x08));
input_report_key(input, BTN_4, (data[6] & 0x10));
input_report_key(input, BTN_5, (data[6] & 0x20));
+ if (data[6] & 0x3f) {
+ input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+ } else {
+ input_report_abs(input, ABS_MISC, 0);
+ }
+ } else if (features->type == WACOM_13HD) {
+ input_report_key(input, BTN_0, (data[3] & 0x01));
+ input_report_key(input, BTN_1, (data[4] & 0x01));
+ input_report_key(input, BTN_2, (data[4] & 0x02));
+ input_report_key(input, BTN_3, (data[4] & 0x04));
+ input_report_key(input, BTN_4, (data[4] & 0x08));
+ input_report_key(input, BTN_5, (data[4] & 0x10));
+ input_report_key(input, BTN_6, (data[4] & 0x20));
+ input_report_key(input, BTN_7, (data[4] & 0x40));
+ input_report_key(input, BTN_8, (data[4] & 0x80));
+ if ((data[3] & 0x01) | data[4]) {
+ input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+ } else {
+ input_report_abs(input, ABS_MISC, 0);
+ }
} else if (features->type == WACOM_24HD) {
input_report_key(input, BTN_0, (data[6] & 0x01));
input_report_key(input, BTN_1, (data[6] & 0x02));
@@ -590,10 +615,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
}
if (data[1] | data[2] | (data[3] & 0x1f) | data[4] | data[6] | data[8]) {
- input_report_key(input, wacom->tool[1], 1);
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
} else {
- input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
} else if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
@@ -618,10 +641,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
}
if (data[2] | (data[3] & 0x01) | data[4] | data[5]) {
- input_report_key(input, wacom->tool[1], 1);
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
} else {
- input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
} else {
@@ -668,10 +689,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
if ((data[5] & 0x1f) | data[6] | (data[1] & 0x1f) |
data[2] | (data[3] & 0x1f) | data[4] | data[8] |
(data[7] & 0x01)) {
- input_report_key(input, wacom->tool[1], 1);
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
} else {
- input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
}
@@ -1301,6 +1320,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case INTUOS4L:
case CINTIQ:
case WACOM_BEE:
+ case WACOM_13HD:
case WACOM_21UX2:
case WACOM_22HD:
case WACOM_24HD:
@@ -1530,15 +1550,15 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(KEY_PROG1, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
/* fall through */
case DTK:
for (i = 0; i < 6; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
- input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
- input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
-
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
wacom_setup_cintiq(wacom_wac);
@@ -1579,6 +1599,15 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
wacom_setup_cintiq(wacom_wac);
break;
+ case WACOM_13HD:
+ for (i = 0; i < 9; i++)
+ __set_bit(BTN_0 + i, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
+ wacom_setup_cintiq(wacom_wac);
+ break;
+
case INTUOS3:
case INTUOS3L:
__set_bit(BTN_4, input_dev->keybit);
@@ -1937,7 +1966,8 @@ static const struct wacom_features wacom_features_0xF4 =
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xF8 =
{ "Wacom Cintiq 24HD touch", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047, /* Pen */
- 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
+ 63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
static const struct wacom_features wacom_features_0xF6 =
{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10 };
@@ -1950,6 +1980,9 @@ static const struct wacom_features wacom_features_0xC5 =
static const struct wacom_features wacom_features_0xC6 =
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023,
63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x304 =
+ { "Wacom Cintiq 13HD", WACOM_PKGLEN_INTUOS, 59552, 33848, 1023,
+ 63, WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xC7 =
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511,
0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1959,6 +1992,9 @@ static const struct wacom_features wacom_features_0xCE =
static const struct wacom_features wacom_features_0xF0 =
{ "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511,
0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x57 =
+ { "Wacom DTK2241", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
+ 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES};
static const struct wacom_features wacom_features_0x59 = /* Pen */
{ "Wacom DTH2242", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
@@ -1972,6 +2008,13 @@ static const struct wacom_features wacom_features_0xCC =
static const struct wacom_features wacom_features_0xFA =
{ "Wacom Cintiq 22HD", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x5B =
+ { "Wacom Cintiq 22HDT", WACOM_PKGLEN_INTUOS, 95840, 54260, 2047,
+ 63, WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
+static const struct wacom_features wacom_features_0x5E =
+ { "Wacom Cintiq 22HDT", .type = WACOM_24HDT,
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5b, .touch_max = 10 };
static const struct wacom_features wacom_features_0x90 =
{ "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2001,7 +2044,7 @@ static const struct wacom_features wacom_features_0xE5 =
static const struct wacom_features wacom_features_0xE6 =
{ "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255,
0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
- .touch_max = 2 };
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xEC =
{ "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2143,8 +2186,11 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x43) },
{ USB_DEVICE_WACOM(0x44) },
{ USB_DEVICE_WACOM(0x45) },
+ { USB_DEVICE_WACOM(0x57) },
{ USB_DEVICE_WACOM(0x59) },
{ USB_DEVICE_DETAILED(0x5D, USB_CLASS_HID, 0, 0) },
+ { USB_DEVICE_WACOM(0x5B) },
+ { USB_DEVICE_DETAILED(0x5E, USB_CLASS_HID, 0, 0) },
{ USB_DEVICE_WACOM(0xB0) },
{ USB_DEVICE_WACOM(0xB1) },
{ USB_DEVICE_WACOM(0xB2) },
@@ -2205,6 +2251,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x100) },
{ USB_DEVICE_WACOM(0x101) },
{ USB_DEVICE_WACOM(0x10D) },
+ { USB_DEVICE_WACOM(0x304) },
{ USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x47) },
{ USB_DEVICE_WACOM(0xF4) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 5f9a772..dfc9e08 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -82,6 +82,7 @@ enum {
WACOM_24HD,
CINTIQ,
WACOM_BEE,
+ WACOM_13HD,
WACOM_MO,
WIRELESS,
BAMBOO_PT,
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
index 17c9097..39f3df8 100644
--- a/drivers/input/touchscreen/egalax_ts.c
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -216,7 +216,7 @@ static int egalax_ts_probe(struct i2c_client *client,
input_set_abs_params(input_dev,
ABS_MT_POSITION_X, 0, EGALAX_MAX_X, 0, 0);
input_set_abs_params(input_dev,
- ABS_MT_POSITION_X, 0, EGALAX_MAX_Y, 0, 0);
+ ABS_MT_POSITION_Y, 0, EGALAX_MAX_Y, 0, 0);
input_mt_init_slots(input_dev, MAX_SUPPORT_POINTS, 0);
input_set_drvdata(input_dev, ts);
diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index 29889bb..63b3d4e 100644
--- a/drivers/irqchip/irq-mxs.c
+++ b/drivers/irqchip/irq-mxs.c
@@ -76,16 +76,10 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
{
u32 irqnr;
- do {
- irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
- if (irqnr != 0x7f) {
- __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
- irqnr = irq_find_mapping(icoll_domain, irqnr);
- handle_IRQ(irqnr, regs);
- continue;
- }
- break;
- } while (1);
+ irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
+ __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
+ irqnr = irq_find_mapping(icoll_domain, irqnr);
+ handle_IRQ(irqnr, regs);
}
static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq,
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
index 065b7a3..47a52ab 100644
--- a/drivers/irqchip/irq-versatile-fpga.c
+++ b/drivers/irqchip/irq-versatile-fpga.c
@@ -119,7 +119,7 @@ static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq,
/* Skip invalid IRQs, only register handlers for the real ones */
if (!(f->valid & BIT(hwirq)))
- return -ENOTSUPP;
+ return -EPERM;
irq_set_chip_data(irq, f);
irq_set_chip_and_handler(irq, &f->chip,
handle_level_irq);
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 884d11c..2bbb004 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -197,7 +197,7 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq,
/* Skip invalid IRQs, only register handlers for the real ones */
if (!(v->valid_sources & (1 << hwirq)))
- return -ENOTSUPP;
+ return -EPERM;
irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq);
irq_set_chip_data(irq, v->base);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index 9b1b274..c123709 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -93,7 +93,7 @@ capi_ctr_put(struct capi_ctr *ctr)
static inline struct capi_ctr *get_capi_ctr_by_nr(u16 contr)
{
- if (contr - 1 >= CAPI_MAXCONTR)
+ if (contr < 1 || contr - 1 >= CAPI_MAXCONTR)
return NULL;
return capi_controller[contr - 1];
@@ -103,7 +103,7 @@ static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid)
{
lockdep_assert_held(&capi_controller_lock);
- if (applid - 1 >= CAPI_MAXAPPL)
+ if (applid < 1 || applid - 1 >= CAPI_MAXAPPL)
return NULL;
return capi_applications[applid - 1];
@@ -111,7 +111,7 @@ static inline struct capi20_appl *__get_capi_appl_by_nr(u16 applid)
static inline struct capi20_appl *get_capi_appl_by_nr(u16 applid)
{
- if (applid - 1 >= CAPI_MAXAPPL)
+ if (applid < 1 || applid - 1 >= CAPI_MAXAPPL)
return NULL;
return rcu_dereference(capi_applications[applid - 1]);
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 88d657d..8b98d53 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -885,7 +885,7 @@ isdn_net_log_skb(struct sk_buff *skb, isdn_net_local *lp)
addinfo[0] = '\0';
/* This check stolen from 2.1.72 dev_queue_xmit_nit() */
- if (p < skb->data || skb->network_header >= skb->tail) {
+ if (p < skb->data || skb_network_header(skb) >= skb_tail_pointer(skb)) {
/* fall back to old isdn_net_log_packet method() */
char *buf = skb->data;
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index a0d931b..b02b679 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -107,6 +107,10 @@ static int create_gpio_led(const struct gpio_led *template,
return 0;
}
+ ret = devm_gpio_request(parent, 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;
@@ -126,10 +130,7 @@ static int create_gpio_led(const struct gpio_led *template,
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- ret = devm_gpio_request_one(parent, template->gpio,
- (led_dat->active_low ^ state) ?
- GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
- template->name);
+ ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
if (ret < 0)
return ret;
diff --git a/drivers/leds/leds-ot200.c b/drivers/leds/leds-ot200.c
index ee14662e..98cae52 100644
--- a/drivers/leds/leds-ot200.c
+++ b/drivers/leds/leds-ot200.c
@@ -47,37 +47,37 @@ static struct ot200_led leds[] = {
{
.name = "led_1",
.port = 0x49,
- .mask = BIT(7),
+ .mask = BIT(6),
},
{
.name = "led_2",
.port = 0x49,
- .mask = BIT(6),
+ .mask = BIT(5),
},
{
.name = "led_3",
.port = 0x49,
- .mask = BIT(5),
+ .mask = BIT(4),
},
{
.name = "led_4",
.port = 0x49,
- .mask = BIT(4),
+ .mask = BIT(3),
},
{
.name = "led_5",
.port = 0x49,
- .mask = BIT(3),
+ .mask = BIT(2),
},
{
.name = "led_6",
.port = 0x49,
- .mask = BIT(2),
+ .mask = BIT(1),
},
{
.name = "led_7",
.port = 0x49,
- .mask = BIT(1),
+ .mask = BIT(0),
}
};
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index 699187a..5b9ac32 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -1002,6 +1002,7 @@ void guest_set_pgd(struct lguest *lg, unsigned long gpgdir, u32 idx)
kill_guest(&lg->cpus[0],
"Cannot populate switcher mapping");
}
+ lg->pgdirs[pgdir].last_host_cpu = -1;
}
}
diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig
index 05c220d..f950c9d 100644
--- a/drivers/md/bcache/Kconfig
+++ b/drivers/md/bcache/Kconfig
@@ -1,7 +1,6 @@
config BCACHE
tristate "Block device as cache"
- select CLOSURES
---help---
Allows a block device to be used as cache for other devices; uses
a btree for indexing and the layout is optimized for SSDs.
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index 340146d..d3e15b4 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -1241,7 +1241,7 @@ void bch_cache_set_stop(struct cache_set *);
struct cache_set *bch_cache_set_alloc(struct cache_sb *);
void bch_btree_cache_free(struct cache_set *);
int bch_btree_cache_alloc(struct cache_set *);
-void bch_writeback_init_cached_dev(struct cached_dev *);
+void bch_cached_dev_writeback_init(struct cached_dev *);
void bch_moving_init_cache_set(struct cache_set *);
void bch_cache_allocator_exit(struct cache *ca);
diff --git a/drivers/md/bcache/stats.c b/drivers/md/bcache/stats.c
index 64e6794..b8730e7 100644
--- a/drivers/md/bcache/stats.c
+++ b/drivers/md/bcache/stats.c
@@ -93,24 +93,6 @@ static struct attribute *bch_stats_files[] = {
};
static KTYPE(bch_stats);
-static void scale_accounting(unsigned long data);
-
-void bch_cache_accounting_init(struct cache_accounting *acc,
- struct closure *parent)
-{
- kobject_init(&acc->total.kobj, &bch_stats_ktype);
- kobject_init(&acc->five_minute.kobj, &bch_stats_ktype);
- kobject_init(&acc->hour.kobj, &bch_stats_ktype);
- kobject_init(&acc->day.kobj, &bch_stats_ktype);
-
- closure_init(&acc->cl, parent);
- init_timer(&acc->timer);
- acc->timer.expires = jiffies + accounting_delay;
- acc->timer.data = (unsigned long) acc;
- acc->timer.function = scale_accounting;
- add_timer(&acc->timer);
-}
-
int bch_cache_accounting_add_kobjs(struct cache_accounting *acc,
struct kobject *parent)
{
@@ -244,3 +226,19 @@ void bch_mark_sectors_bypassed(struct search *s, int sectors)
atomic_add(sectors, &dc->accounting.collector.sectors_bypassed);
atomic_add(sectors, &s->op.c->accounting.collector.sectors_bypassed);
}
+
+void bch_cache_accounting_init(struct cache_accounting *acc,
+ struct closure *parent)
+{
+ kobject_init(&acc->total.kobj, &bch_stats_ktype);
+ kobject_init(&acc->five_minute.kobj, &bch_stats_ktype);
+ kobject_init(&acc->hour.kobj, &bch_stats_ktype);
+ kobject_init(&acc->day.kobj, &bch_stats_ktype);
+
+ closure_init(&acc->cl, parent);
+ init_timer(&acc->timer);
+ acc->timer.expires = jiffies + accounting_delay;
+ acc->timer.data = (unsigned long) acc;
+ acc->timer.function = scale_accounting;
+ add_timer(&acc->timer);
+}
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index c8046bc..f88e2b6 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -634,11 +634,10 @@ static int open_dev(struct block_device *b, fmode_t mode)
return 0;
}
-static int release_dev(struct gendisk *b, fmode_t mode)
+static void release_dev(struct gendisk *b, fmode_t mode)
{
struct bcache_device *d = b->private_data;
closure_put(&d->cl);
- return 0;
}
static int ioctl_dev(struct block_device *b, fmode_t mode,
@@ -732,8 +731,7 @@ static void bcache_device_free(struct bcache_device *d)
if (d->c)
bcache_device_detach(d);
-
- if (d->disk)
+ if (d->disk && d->disk->flags & GENHD_FL_UP)
del_gendisk(d->disk);
if (d->disk && d->disk->queue)
blk_cleanup_queue(d->disk->queue);
@@ -756,12 +754,9 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size)
if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
!(d->unaligned_bvec = mempool_create_kmalloc_pool(1,
sizeof(struct bio_vec) * BIO_MAX_PAGES)) ||
- bio_split_pool_init(&d->bio_split_hook))
-
- return -ENOMEM;
-
- d->disk = alloc_disk(1);
- if (!d->disk)
+ bio_split_pool_init(&d->bio_split_hook) ||
+ !(d->disk = alloc_disk(1)) ||
+ !(q = blk_alloc_queue(GFP_KERNEL)))
return -ENOMEM;
snprintf(d->disk->disk_name, DISK_NAME_LEN, "bcache%i", bcache_minor);
@@ -771,10 +766,6 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size)
d->disk->fops = &bcache_ops;
d->disk->private_data = d;
- q = blk_alloc_queue(GFP_KERNEL);
- if (!q)
- return -ENOMEM;
-
blk_queue_make_request(q, NULL);
d->disk->queue = q;
q->queuedata = d;
@@ -999,14 +990,17 @@ static void cached_dev_free(struct closure *cl)
mutex_lock(&bch_register_lock);
- bd_unlink_disk_holder(dc->bdev, dc->disk.disk);
+ if (atomic_read(&dc->running))
+ bd_unlink_disk_holder(dc->bdev, dc->disk.disk);
bcache_device_free(&dc->disk);
list_del(&dc->list);
mutex_unlock(&bch_register_lock);
if (!IS_ERR_OR_NULL(dc->bdev)) {
- blk_sync_queue(bdev_get_queue(dc->bdev));
+ if (dc->bdev->bd_disk)
+ blk_sync_queue(bdev_get_queue(dc->bdev));
+
blkdev_put(dc->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
}
@@ -1028,73 +1022,67 @@ static void cached_dev_flush(struct closure *cl)
static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
{
- int err;
+ int ret;
struct io *io;
-
- closure_init(&dc->disk.cl, NULL);
- set_closure_fn(&dc->disk.cl, cached_dev_flush, system_wq);
+ struct request_queue *q = bdev_get_queue(dc->bdev);
__module_get(THIS_MODULE);
INIT_LIST_HEAD(&dc->list);
+ closure_init(&dc->disk.cl, NULL);
+ set_closure_fn(&dc->disk.cl, cached_dev_flush, system_wq);
kobject_init(&dc->disk.kobj, &bch_cached_dev_ktype);
-
- bch_cache_accounting_init(&dc->accounting, &dc->disk.cl);
-
- err = bcache_device_init(&dc->disk, block_size);
- if (err)
- goto err;
-
- spin_lock_init(&dc->io_lock);
- closure_init_unlocked(&dc->sb_write);
INIT_WORK(&dc->detach, cached_dev_detach_finish);
+ closure_init_unlocked(&dc->sb_write);
+ INIT_LIST_HEAD(&dc->io_lru);
+ spin_lock_init(&dc->io_lock);
+ bch_cache_accounting_init(&dc->accounting, &dc->disk.cl);
dc->sequential_merge = true;
dc->sequential_cutoff = 4 << 20;
- INIT_LIST_HEAD(&dc->io_lru);
- dc->sb_bio.bi_max_vecs = 1;
- dc->sb_bio.bi_io_vec = dc->sb_bio.bi_inline_vecs;
-
for (io = dc->io; io < dc->io + RECENT_IO; io++) {
list_add(&io->lru, &dc->io_lru);
hlist_add_head(&io->hash, dc->io_hash + RECENT_IO);
}
- bch_writeback_init_cached_dev(dc);
+ ret = bcache_device_init(&dc->disk, block_size);
+ if (ret)
+ return ret;
+
+ set_capacity(dc->disk.disk,
+ dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
+
+ dc->disk.disk->queue->backing_dev_info.ra_pages =
+ max(dc->disk.disk->queue->backing_dev_info.ra_pages,
+ q->backing_dev_info.ra_pages);
+
+ bch_cached_dev_request_init(dc);
+ bch_cached_dev_writeback_init(dc);
return 0;
-err:
- bcache_device_stop(&dc->disk);
- return err;
}
/* Cached device - bcache superblock */
-static const char *register_bdev(struct cache_sb *sb, struct page *sb_page,
+static void register_bdev(struct cache_sb *sb, struct page *sb_page,
struct block_device *bdev,
struct cached_dev *dc)
{
char name[BDEVNAME_SIZE];
const char *err = "cannot allocate memory";
- struct gendisk *g;
struct cache_set *c;
- if (!dc || cached_dev_init(dc, sb->block_size << 9) != 0)
- return err;
-
memcpy(&dc->sb, sb, sizeof(struct cache_sb));
- dc->sb_bio.bi_io_vec[0].bv_page = sb_page;
dc->bdev = bdev;
dc->bdev->bd_holder = dc;
- g = dc->disk.disk;
-
- set_capacity(g, dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
-
- g->queue->backing_dev_info.ra_pages =
- max(g->queue->backing_dev_info.ra_pages,
- bdev->bd_queue->backing_dev_info.ra_pages);
+ bio_init(&dc->sb_bio);
+ dc->sb_bio.bi_max_vecs = 1;
+ dc->sb_bio.bi_io_vec = dc->sb_bio.bi_inline_vecs;
+ dc->sb_bio.bi_io_vec[0].bv_page = sb_page;
+ get_page(sb_page);
- bch_cached_dev_request_init(dc);
+ if (cached_dev_init(dc, sb->block_size << 9))
+ goto err;
err = "error creating kobject";
if (kobject_add(&dc->disk.kobj, &part_to_dev(bdev->bd_part)->kobj,
@@ -1103,6 +1091,8 @@ static const char *register_bdev(struct cache_sb *sb, struct page *sb_page,
if (bch_cache_accounting_add_kobjs(&dc->accounting, &dc->disk.kobj))
goto err;
+ pr_info("registered backing device %s", bdevname(bdev, name));
+
list_add(&dc->list, &uncached_devices);
list_for_each_entry(c, &bch_cache_sets, list)
bch_cached_dev_attach(dc, c);
@@ -1111,15 +1101,10 @@ static const char *register_bdev(struct cache_sb *sb, struct page *sb_page,
BDEV_STATE(&dc->sb) == BDEV_STATE_STALE)
bch_cached_dev_run(dc);
- return NULL;
+ return;
err:
- kobject_put(&dc->disk.kobj);
pr_notice("error opening %s: %s", bdevname(bdev, name), err);
- /*
- * Return NULL instead of an error because kobject_put() cleans
- * everything up
- */
- return NULL;
+ bcache_device_stop(&dc->disk);
}
/* Flash only volumes */
@@ -1717,20 +1702,11 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
size_t free;
struct bucket *b;
- if (!ca)
- return -ENOMEM;
-
__module_get(THIS_MODULE);
kobject_init(&ca->kobj, &bch_cache_ktype);
- memcpy(&ca->sb, sb, sizeof(struct cache_sb));
-
INIT_LIST_HEAD(&ca->discards);
- bio_init(&ca->sb_bio);
- ca->sb_bio.bi_max_vecs = 1;
- ca->sb_bio.bi_io_vec = ca->sb_bio.bi_inline_vecs;
-
bio_init(&ca->journal.bio);
ca->journal.bio.bi_max_vecs = 8;
ca->journal.bio.bi_io_vec = ca->journal.bio.bi_inline_vecs;
@@ -1742,18 +1718,17 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
!init_fifo(&ca->free_inc, free << 2, GFP_KERNEL) ||
!init_fifo(&ca->unused, free << 2, GFP_KERNEL) ||
!init_heap(&ca->heap, free << 3, GFP_KERNEL) ||
- !(ca->buckets = vmalloc(sizeof(struct bucket) *
+ !(ca->buckets = vzalloc(sizeof(struct bucket) *
ca->sb.nbuckets)) ||
!(ca->prio_buckets = kzalloc(sizeof(uint64_t) * prio_buckets(ca) *
2, GFP_KERNEL)) ||
!(ca->disk_buckets = alloc_bucket_pages(GFP_KERNEL, ca)) ||
!(ca->alloc_workqueue = alloc_workqueue("bch_allocator", 0, 1)) ||
bio_split_pool_init(&ca->bio_split_hook))
- goto err;
+ return -ENOMEM;
ca->prio_last_buckets = ca->prio_buckets + prio_buckets(ca);
- memset(ca->buckets, 0, ca->sb.nbuckets * sizeof(struct bucket));
for_each_bucket(b, ca)
atomic_set(&b->pin, 0);
@@ -1766,22 +1741,28 @@ err:
return -ENOMEM;
}
-static const char *register_cache(struct cache_sb *sb, struct page *sb_page,
+static void register_cache(struct cache_sb *sb, struct page *sb_page,
struct block_device *bdev, struct cache *ca)
{
char name[BDEVNAME_SIZE];
const char *err = "cannot allocate memory";
- if (cache_alloc(sb, ca) != 0)
- return err;
-
- ca->sb_bio.bi_io_vec[0].bv_page = sb_page;
+ memcpy(&ca->sb, sb, sizeof(struct cache_sb));
ca->bdev = bdev;
ca->bdev->bd_holder = ca;
+ bio_init(&ca->sb_bio);
+ ca->sb_bio.bi_max_vecs = 1;
+ ca->sb_bio.bi_io_vec = ca->sb_bio.bi_inline_vecs;
+ ca->sb_bio.bi_io_vec[0].bv_page = sb_page;
+ get_page(sb_page);
+
if (blk_queue_discard(bdev_get_queue(ca->bdev)))
ca->discard = CACHE_DISCARD(&ca->sb);
+ if (cache_alloc(sb, ca) != 0)
+ goto err;
+
err = "error creating kobject";
if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache"))
goto err;
@@ -1791,15 +1772,10 @@ static const char *register_cache(struct cache_sb *sb, struct page *sb_page,
goto err;
pr_info("registered cache device %s", bdevname(bdev, name));
-
- return NULL;
+ return;
err:
+ pr_notice("error opening %s: %s", bdevname(bdev, name), err);
kobject_put(&ca->kobj);
- pr_info("error opening %s: %s", bdevname(bdev, name), err);
- /* Return NULL instead of an error because kobject_put() cleans
- * everything up
- */
- return NULL;
}
/* Global interfaces/init */
@@ -1833,12 +1809,15 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
bdev = blkdev_get_by_path(strim(path),
FMODE_READ|FMODE_WRITE|FMODE_EXCL,
sb);
- if (bdev == ERR_PTR(-EBUSY))
- err = "device busy";
-
- if (IS_ERR(bdev) ||
- set_blocksize(bdev, 4096))
+ if (IS_ERR(bdev)) {
+ if (bdev == ERR_PTR(-EBUSY))
+ err = "device busy";
goto err;
+ }
+
+ err = "failed to set blocksize";
+ if (set_blocksize(bdev, 4096))
+ goto err_close;
err = read_super(sb, bdev, &sb_page);
if (err)
@@ -1846,33 +1825,33 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
if (SB_IS_BDEV(sb)) {
struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
+ if (!dc)
+ goto err_close;
- err = register_bdev(sb, sb_page, bdev, dc);
+ register_bdev(sb, sb_page, bdev, dc);
} else {
struct cache *ca = kzalloc(sizeof(*ca), GFP_KERNEL);
+ if (!ca)
+ goto err_close;
- err = register_cache(sb, sb_page, bdev, ca);
+ register_cache(sb, sb_page, bdev, ca);
}
-
- if (err) {
- /* register_(bdev|cache) will only return an error if they
- * didn't get far enough to create the kobject - if they did,
- * the kobject destructor will do this cleanup.
- */
+out:
+ if (sb_page)
put_page(sb_page);
-err_close:
- blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
-err:
- if (attr != &ksysfs_register_quiet)
- pr_info("error opening %s: %s", path, err);
- ret = -EINVAL;
- }
-
kfree(sb);
kfree(path);
mutex_unlock(&bch_register_lock);
module_put(THIS_MODULE);
return ret;
+
+err_close:
+ blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
+err:
+ if (attr != &ksysfs_register_quiet)
+ pr_info("error opening %s: %s", path, err);
+ ret = -EINVAL;
+ goto out;
}
static int bcache_reboot(struct notifier_block *n, unsigned long code, void *x)
diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c
index 93e7e31..2714ed3 100644
--- a/drivers/md/bcache/writeback.c
+++ b/drivers/md/bcache/writeback.c
@@ -375,7 +375,7 @@ err:
refill_dirty(cl);
}
-void bch_writeback_init_cached_dev(struct cached_dev *dc)
+void bch_cached_dev_writeback_init(struct cached_dev *dc)
{
closure_init_unlocked(&dc->writeback);
init_rwsem(&dc->writeback_lock);
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 759cffc..88f2f80 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -2188,7 +2188,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
*need_commit = false;
- metadata_dev_size = get_metadata_dev_size(pool->md_dev);
+ metadata_dev_size = get_metadata_dev_size_in_blocks(pool->md_dev);
r = dm_pool_get_metadata_dev_size(pool->pmd, &sb_metadata_dev_size);
if (r) {
@@ -2197,7 +2197,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
}
if (metadata_dev_size < sb_metadata_dev_size) {
- DMERR("metadata device (%llu sectors) too small: expected %llu",
+ DMERR("metadata device (%llu blocks) too small: expected %llu",
metadata_dev_size, sb_metadata_dev_size);
return -EINVAL;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 681d109..9b82377 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -5268,8 +5268,8 @@ static void md_clean(struct mddev *mddev)
static void __md_stop_writes(struct mddev *mddev)
{
+ set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
if (mddev->sync_thread) {
- set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
md_reap_sync_thread(mddev);
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 5595118..6e17f81 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -417,7 +417,17 @@ static void raid1_end_write_request(struct bio *bio, int error)
r1_bio->bios[mirror] = NULL;
to_put = bio;
- set_bit(R1BIO_Uptodate, &r1_bio->state);
+ /*
+ * Do not set R1BIO_Uptodate if the current device is
+ * rebuilding or Faulty. This is because we cannot use
+ * such device for properly reading the data back (we could
+ * potentially use it, if the current write would have felt
+ * before rdev->recovery_offset, but for simplicity we don't
+ * check this here.
+ */
+ if (test_bit(In_sync, &conf->mirrors[mirror].rdev->flags) &&
+ !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags))
+ set_bit(R1BIO_Uptodate, &r1_bio->state);
/* Maybe we can clear some bad blocks. */
if (is_badblock(conf->mirrors[mirror].rdev,
@@ -870,17 +880,17 @@ static void allow_barrier(struct r1conf *conf)
wake_up(&conf->wait_barrier);
}
-static void freeze_array(struct r1conf *conf)
+static void freeze_array(struct r1conf *conf, int extra)
{
/* stop syncio and normal IO and wait for everything to
* go quite.
* We increment barrier and nr_waiting, and then
- * wait until nr_pending match nr_queued+1
+ * wait until nr_pending match nr_queued+extra
* This is called in the context of one normal IO request
* that has failed. Thus any sync request that might be pending
* will be blocked by nr_pending, and we need to wait for
* pending IO requests to complete or be queued for re-try.
- * Thus the number queued (nr_queued) plus this request (1)
+ * Thus the number queued (nr_queued) plus this request (extra)
* must match the number of pending IOs (nr_pending) before
* we continue.
*/
@@ -888,7 +898,7 @@ static void freeze_array(struct r1conf *conf)
conf->barrier++;
conf->nr_waiting++;
wait_event_lock_irq_cmd(conf->wait_barrier,
- conf->nr_pending == conf->nr_queued+1,
+ conf->nr_pending == conf->nr_queued+extra,
conf->resync_lock,
flush_pending_writes(conf));
spin_unlock_irq(&conf->resync_lock);
@@ -1544,8 +1554,8 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
* we wait for all outstanding requests to complete.
*/
synchronize_sched();
- raise_barrier(conf);
- lower_barrier(conf);
+ freeze_array(conf, 0);
+ unfreeze_array(conf);
clear_bit(Unmerged, &rdev->flags);
}
md_integrity_add_rdev(rdev, mddev);
@@ -1595,11 +1605,11 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
*/
struct md_rdev *repl =
conf->mirrors[conf->raid_disks + number].rdev;
- raise_barrier(conf);
+ freeze_array(conf, 0);
clear_bit(Replacement, &repl->flags);
p->rdev = repl;
conf->mirrors[conf->raid_disks + number].rdev = NULL;
- lower_barrier(conf);
+ unfreeze_array(conf);
clear_bit(WantReplacement, &rdev->flags);
} else
clear_bit(WantReplacement, &rdev->flags);
@@ -2195,7 +2205,7 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
* frozen
*/
if (mddev->ro == 0) {
- freeze_array(conf);
+ freeze_array(conf, 1);
fix_read_error(conf, r1_bio->read_disk,
r1_bio->sector, r1_bio->sectors);
unfreeze_array(conf);
@@ -2780,8 +2790,8 @@ static int run(struct mddev *mddev)
return PTR_ERR(conf);
if (mddev->queue)
- blk_queue_max_write_same_sectors(mddev->queue,
- mddev->chunk_sectors);
+ blk_queue_max_write_same_sectors(mddev->queue, 0);
+
rdev_for_each(rdev, mddev) {
if (!mddev->gendisk)
continue;
@@ -2963,7 +2973,7 @@ static int raid1_reshape(struct mddev *mddev)
return -ENOMEM;
}
- raise_barrier(conf);
+ freeze_array(conf, 0);
/* ok, everything is stopped */
oldpool = conf->r1bio_pool;
@@ -2994,7 +3004,7 @@ static int raid1_reshape(struct mddev *mddev)
conf->raid_disks = mddev->raid_disks = raid_disks;
mddev->delta_disks = 0;
- lower_barrier(conf);
+ unfreeze_array(conf);
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 59d4daa..6ddae25 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -490,7 +490,17 @@ static void raid10_end_write_request(struct bio *bio, int error)
sector_t first_bad;
int bad_sectors;
- set_bit(R10BIO_Uptodate, &r10_bio->state);
+ /*
+ * Do not set R10BIO_Uptodate if the current device is
+ * rebuilding or Faulty. This is because we cannot use
+ * such device for properly reading the data back (we could
+ * potentially use it, if the current write would have felt
+ * before rdev->recovery_offset, but for simplicity we don't
+ * check this here.
+ */
+ if (test_bit(In_sync, &rdev->flags) &&
+ !test_bit(Faulty, &rdev->flags))
+ set_bit(R10BIO_Uptodate, &r10_bio->state);
/* Maybe we can clear some bad blocks. */
if (is_badblock(rdev,
@@ -1055,17 +1065,17 @@ static void allow_barrier(struct r10conf *conf)
wake_up(&conf->wait_barrier);
}
-static void freeze_array(struct r10conf *conf)
+static void freeze_array(struct r10conf *conf, int extra)
{
/* stop syncio and normal IO and wait for everything to
* go quiet.
* We increment barrier and nr_waiting, and then
- * wait until nr_pending match nr_queued+1
+ * wait until nr_pending match nr_queued+extra
* This is called in the context of one normal IO request
* that has failed. Thus any sync request that might be pending
* will be blocked by nr_pending, and we need to wait for
* pending IO requests to complete or be queued for re-try.
- * Thus the number queued (nr_queued) plus this request (1)
+ * Thus the number queued (nr_queued) plus this request (extra)
* must match the number of pending IOs (nr_pending) before
* we continue.
*/
@@ -1073,7 +1083,7 @@ static void freeze_array(struct r10conf *conf)
conf->barrier++;
conf->nr_waiting++;
wait_event_lock_irq_cmd(conf->wait_barrier,
- conf->nr_pending == conf->nr_queued+1,
+ conf->nr_pending == conf->nr_queued+extra,
conf->resync_lock,
flush_pending_writes(conf));
@@ -1837,8 +1847,8 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
* we wait for all outstanding requests to complete.
*/
synchronize_sched();
- raise_barrier(conf, 0);
- lower_barrier(conf);
+ freeze_array(conf, 0);
+ unfreeze_array(conf);
clear_bit(Unmerged, &rdev->flags);
}
md_integrity_add_rdev(rdev, mddev);
@@ -2612,7 +2622,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
r10_bio->devs[slot].bio = NULL;
if (mddev->ro == 0) {
- freeze_array(conf);
+ freeze_array(conf, 1);
fix_read_error(conf, mddev, r10_bio);
unfreeze_array(conf);
} else
@@ -3609,8 +3619,7 @@ static int run(struct mddev *mddev)
if (mddev->queue) {
blk_queue_max_discard_sectors(mddev->queue,
mddev->chunk_sectors);
- blk_queue_max_write_same_sectors(mddev->queue,
- mddev->chunk_sectors);
+ blk_queue_max_write_same_sectors(mddev->queue, 0);
blk_queue_io_min(mddev->queue, chunk_size);
if (conf->geo.raid_disks % conf->geo.near_copies)
blk_queue_io_opt(mddev->queue, chunk_size * conf->geo.raid_disks);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 9359828..05e4a10 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -664,6 +664,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags))
bi->bi_rw |= REQ_FLUSH;
+ bi->bi_vcnt = 1;
bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
bi->bi_io_vec[0].bv_offset = 0;
bi->bi_size = STRIPE_SIZE;
@@ -701,6 +702,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
else
rbi->bi_sector = (sh->sector
+ rrdev->data_offset);
+ rbi->bi_vcnt = 1;
rbi->bi_io_vec[0].bv_len = STRIPE_SIZE;
rbi->bi_io_vec[0].bv_offset = 0;
rbi->bi_size = STRIPE_SIZE;
@@ -5464,7 +5466,7 @@ static int run(struct mddev *mddev)
if (mddev->major_version == 0 &&
mddev->minor_version > 90)
rdev->recovery_offset = reshape_offset;
-
+
if (rdev->recovery_offset < reshape_offset) {
/* We need to check old and new layout */
if (!only_parity(rdev->raid_disk,
@@ -5587,6 +5589,8 @@ static int run(struct mddev *mddev)
*/
mddev->queue->limits.discard_zeroes_data = 0;
+ blk_queue_max_write_same_sectors(mddev->queue, 0);
+
rdev_for_each(rdev, mddev) {
disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9);
diff --git a/drivers/media/pci/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h
index ca2754a..5e04008 100644
--- a/drivers/media/pci/zoran/zoran.h
+++ b/drivers/media/pci/zoran/zoran.h
@@ -176,7 +176,7 @@ struct zoran_fh;
struct zoran_mapping {
struct zoran_fh *fh;
- int count;
+ atomic_t count;
};
struct zoran_buffer {
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index 1168a84..d133c30 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -2803,8 +2803,7 @@ static void
zoran_vm_open (struct vm_area_struct *vma)
{
struct zoran_mapping *map = vma->vm_private_data;
-
- map->count++;
+ atomic_inc(&map->count);
}
static void
@@ -2815,7 +2814,7 @@ zoran_vm_close (struct vm_area_struct *vma)
struct zoran *zr = fh->zr;
int i;
- if (--map->count > 0)
+ if (!atomic_dec_and_mutex_lock(&map->count, &zr->resource_lock))
return;
dprintk(3, KERN_INFO "%s: %s - munmap(%s)\n", ZR_DEVNAME(zr),
@@ -2828,14 +2827,16 @@ zoran_vm_close (struct vm_area_struct *vma)
kfree(map);
/* Any buffers still mapped? */
- for (i = 0; i < fh->buffers.num_buffers; i++)
- if (fh->buffers.buffer[i].map)
+ for (i = 0; i < fh->buffers.num_buffers; i++) {
+ if (fh->buffers.buffer[i].map) {
+ mutex_unlock(&zr->resource_lock);
return;
+ }
+ }
dprintk(3, KERN_INFO "%s: %s - free %s buffers\n", ZR_DEVNAME(zr),
__func__, mode_name(fh->map_mode));
- mutex_lock(&zr->resource_lock);
if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
if (fh->buffers.active != ZORAN_FREE) {
@@ -2939,7 +2940,7 @@ zoran_mmap (struct file *file,
goto mmap_unlock_and_return;
}
map->fh = fh;
- map->count = 1;
+ atomic_set(&map->count, 1);
vma->vm_ops = &zoran_vm_ops;
vma->vm_flags |= VM_DONTEXPAND;
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 477268a..d338b19 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -2150,6 +2150,9 @@ static int __init omap_vout_probe(struct platform_device *pdev)
struct omap_dss_device *def_display;
struct omap2video_device *vid_dev = NULL;
+ if (omapdss_is_initialized() == false)
+ return -EPROBE_DEFER;
+
ret = omapdss_compat_init();
if (ret) {
dev_err(&pdev->dev, "failed to init dss\n");
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index cadf1cc..04644e7 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -1560,12 +1560,6 @@ static int __init_or_module emif_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, emif);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(emif->dev, "%s: error getting memory resource\n",
- __func__);
- goto error;
- }
-
emif->base = devm_ioremap_resource(emif->dev, res);
if (IS_ERR(emif->base))
goto error;
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d9aed15..d54e985 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -579,7 +579,7 @@ config AB8500_CORE
config AB8500_DEBUG
bool "Enable debug info via debugfs"
- depends on AB8500_CORE && DEBUG_FS
+ depends on AB8500_GPADC && DEBUG_FS
default y if DEBUG_FS
help
Select this option if you want debug information using the debug
@@ -818,6 +818,7 @@ config MFD_TPS65910
config MFD_TPS65912
bool "TI TPS65912 Power Management chip"
depends on GPIOLIB
+ select MFD_CORE
help
If you say yes here you get support for the TPS65912 series of
PM chips.
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 8e8a016..258b367 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -868,6 +868,15 @@ static struct resource ab8500_chargalg_resources[] = {};
#ifdef CONFIG_DEBUG_FS
static struct resource ab8500_debug_resources[] = {
{
+ .name = "IRQ_AB8500",
+ /*
+ * Number will be filled in. NOTE: this is deliberately
+ * not flagged as an IRQ in ordet to avoid remapping using
+ * the irqdomain in the MFD core, so that this IRQ passes
+ * unremapped to the debug code.
+ */
+ },
+ {
.name = "IRQ_FIRST",
.start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
.end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
@@ -1051,6 +1060,7 @@ static struct mfd_cell ab8500_devs[] = {
},
{
.name = "ab8500-gpadc",
+ .of_compatible = "stericsson,ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
.resources = ab8500_gpadc_resources,
},
@@ -1097,7 +1107,7 @@ static struct mfd_cell ab8500_devs[] = {
.of_compatible = "stericsson,ab8500-denc",
},
{
- .name = "ab8500-gpio",
+ .name = "pinctrl-ab8500",
.of_compatible = "stericsson,ab8500-gpio",
},
{
@@ -1208,6 +1218,7 @@ static struct mfd_cell ab8505_devs[] = {
},
{
.name = "ab8500-gpadc",
+ .of_compatible = "stericsson,ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
.resources = ab8505_gpadc_resources,
},
@@ -1234,7 +1245,7 @@ static struct mfd_cell ab8505_devs[] = {
.name = "ab8500-leds",
},
{
- .name = "ab8500-gpio",
+ .name = "pinctrl-ab8505",
},
{
.name = "ab8500-usb",
@@ -1271,6 +1282,7 @@ static struct mfd_cell ab8540_devs[] = {
},
{
.name = "ab8500-gpadc",
+ .of_compatible = "stericsson,ab8500-gpadc",
.num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
.resources = ab8505_gpadc_resources,
},
@@ -1302,7 +1314,7 @@ static struct mfd_cell ab8540_devs[] = {
.resources = ab8500_temp_resources,
},
{
- .name = "ab8500-gpio",
+ .name = "pinctrl-ab8540",
},
{
.name = "ab8540-usb",
@@ -1712,6 +1724,12 @@ static int ab8500_probe(struct platform_device *pdev)
if (ret)
return ret;
+#if CONFIG_DEBUG_FS
+ /* Pass to debugfs */
+ ab8500_debug_resources[0].start = ab8500->irq;
+ ab8500_debug_resources[0].end = ab8500->irq;
+#endif
+
if (is_ab9540(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index b88bbbc..37b7ce4c7 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -91,12 +91,10 @@
#include <linux/ctype.h>
#endif
-/* TODO: this file should not reference IRQ_DB8500_AB8500! */
-#include <mach/irqs.h>
-
static u32 debug_bank;
static u32 debug_address;
+static int irq_ab8500;
static int irq_first;
static int irq_last;
static u32 *irq_count;
@@ -1589,7 +1587,7 @@ void ab8500_debug_register_interrupt(int line)
{
if (line < num_interrupt_lines) {
num_interrupts[line]++;
- if (suspend_test_wake_cause_interrupt_is_mine(IRQ_DB8500_AB8500))
+ if (suspend_test_wake_cause_interrupt_is_mine(irq_ab8500))
num_wake_interrupts[line]++;
}
}
@@ -2941,6 +2939,7 @@ static int ab8500_debug_probe(struct platform_device *plf)
struct dentry *file;
int ret = -ENOMEM;
struct ab8500 *ab8500;
+ struct resource *res;
debug_bank = AB8500_MISC;
debug_address = AB8500_REV_REG & 0x00FF;
@@ -2959,6 +2958,15 @@ static int ab8500_debug_probe(struct platform_device *plf)
if (!event_name)
goto out_freedev_attr;
+ res = platform_get_resource_byname(plf, 0, "IRQ_AB8500");
+ if (!res) {
+ dev_err(&plf->dev, "AB8500 irq not found, err %d\n",
+ irq_first);
+ ret = -ENXIO;
+ goto out_freeevent_name;
+ }
+ irq_ab8500 = res->start;
+
irq_first = platform_get_irq_byname(plf, "IRQ_FIRST");
if (irq_first < 0) {
dev_err(&plf->dev, "First irq not found, err %d\n",
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 5e65b28..13f7866 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -907,14 +907,17 @@ static int ab8500_gpadc_suspend(struct device *dev)
static int ab8500_gpadc_resume(struct device *dev)
{
struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+ int ret;
- regulator_enable(gpadc->regu);
+ ret = regulator_enable(gpadc->regu);
+ if (ret)
+ dev_err(dev, "Failed to enable vtvout LDO: %d\n", ret);
pm_runtime_mark_last_busy(gpadc->dev);
pm_runtime_put_autosuspend(gpadc->dev);
mutex_unlock(&gpadc->ab8500_gpadc_lock);
- return 0;
+ return ret;
}
static int ab8500_gpadc_probe(struct platform_device *pdev)
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index fbca1ce..8e0dae5 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -23,7 +23,7 @@
static struct device *sysctrl_dev;
-void ab8500_power_off(void)
+static void ab8500_power_off(void)
{
sigset_t old;
sigset_t all;
@@ -104,7 +104,7 @@ void ab8500_restart(char mode, const char *cmd)
plat = dev_get_platdata(sysctrl_dev->parent);
pdata = plat->sysctrl;
- if (pdata->reboot_reason_code)
+ if (pdata && pdata->reboot_reason_code)
reason = pdata->reboot_reason_code(cmd);
else
pr_warn("[%s] No reboot reason set. Default reason %d\n",
@@ -188,14 +188,15 @@ static int ab8500_sysctrl_probe(struct platform_device *pdev)
plat = dev_get_platdata(pdev->dev.parent);
- if (!(plat && plat->sysctrl))
+ if (!plat)
return -EINVAL;
- if (plat->pm_power_off)
+ sysctrl_dev = &pdev->dev;
+
+ if (!pm_power_off)
pm_power_off = ab8500_power_off;
pdata = plat->sysctrl;
-
if (pdata) {
int last, ret, i, j;
@@ -226,6 +227,10 @@ static int ab8500_sysctrl_probe(struct platform_device *pdev)
static int ab8500_sysctrl_remove(struct platform_device *pdev)
{
sysctrl_dev = NULL;
+
+ if (pm_power_off == ab8500_power_off)
+ pm_power_off = NULL;
+
return 0;
}
diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c
index 9818afb..3714acb 100644
--- a/drivers/mfd/abx500-core.c
+++ b/drivers/mfd/abx500-core.c
@@ -156,7 +156,7 @@ EXPORT_SYMBOL(abx500_startup_irq_enabled);
void abx500_dump_all_banks(void)
{
struct abx500_ops *ops;
- struct device dummy_child = {0};
+ struct device dummy_child = {NULL};
struct abx500_device_entry *dev_entry;
list_for_each_entry(dev_entry, &abx500_list, list) {
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c
index 19193cf..367ccb5 100644
--- a/drivers/mfd/cros_ec_spi.c
+++ b/drivers/mfd/cros_ec_spi.c
@@ -120,7 +120,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) {
if (*ptr == EC_MSG_HEADER) {
- dev_dbg(ec_dev->dev, "msg found at %ld\n",
+ dev_dbg(ec_dev->dev, "msg found at %zd\n",
ptr - ec_dev->din);
break;
}
@@ -154,7 +154,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
* maximum-supported transfer size.
*/
todo = min(need_len, 256);
- dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%ld\n",
+ dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%zd\n",
todo, need_len, ptr - ec_dev->din);
memset(&trans, '\0', sizeof(trans));
@@ -178,7 +178,7 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
need_len -= todo;
}
- dev_dbg(ec_dev->dev, "loop done, ptr=%ld\n", ptr - ec_dev->din);
+ dev_dbg(ec_dev->dev, "loop done, ptr=%zd\n", ptr - ec_dev->din);
return 0;
}
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 319b8ab..66f8097 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -1613,6 +1613,8 @@ static unsigned long dsiclk_rate(u8 n)
if (divsel == PRCM_DSI_PLLOUT_SEL_OFF)
divsel = dsiclk[n].divsel;
+ else
+ dsiclk[n].divsel = divsel;
switch (divsel) {
case PRCM_DSI_PLLOUT_SEL_PHI_4:
@@ -3095,6 +3097,7 @@ static struct mfd_cell db8500_prcmu_devs[] = {
.num_resources = ARRAY_SIZE(db8500_thsens_resources),
.resources = db8500_thsens_resources,
.platform_data = &db8500_thsens_data,
+ .pdata_size = sizeof(db8500_thsens_data),
},
};
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c
index 5be3b5e..d8d5137 100644
--- a/drivers/mfd/intel_msic.c
+++ b/drivers/mfd/intel_msic.c
@@ -414,11 +414,6 @@ static int intel_msic_probe(struct platform_device *pdev)
* the clients via intel_msic_irq_read().
*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to get SRAM iomem resource\n");
- return -ENODEV;
- }
-
msic->irq_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(msic->irq_base))
return PTR_ERR(msic->irq_base);
diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c
index de48b4e..6f1ef63 100644
--- a/drivers/mfd/si476x-cmd.c
+++ b/drivers/mfd/si476x-cmd.c
@@ -29,6 +29,8 @@
#include <linux/mfd/si476x-core.h>
+#include <asm/unaligned.h>
+
#define msb(x) ((u8)((u16) x >> 8))
#define lsb(x) ((u8)((u16) x & 0x00FF))
@@ -150,7 +152,7 @@ enum si476x_acf_status_report_bits {
SI476X_ACF_SOFTMUTE_INT = (1 << 0),
SI476X_ACF_SMUTE = (1 << 0),
- SI476X_ACF_SMATTN = 0b11111,
+ SI476X_ACF_SMATTN = 0x1f,
SI476X_ACF_PILOT = (1 << 7),
SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT,
};
@@ -483,7 +485,7 @@ int si476x_core_cmd_get_property(struct si476x_core *core, u16 property)
if (err < 0)
return err;
else
- return be16_to_cpup((__be16 *)(resp + 2));
+ return get_unaligned_be16(resp + 2);
}
EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property);
@@ -772,18 +774,18 @@ int si476x_core_cmd_am_rsq_status(struct si476x_core *core,
if (!report)
return err;
- report->snrhint = 0b00001000 & resp[1];
- report->snrlint = 0b00000100 & resp[1];
- report->rssihint = 0b00000010 & resp[1];
- report->rssilint = 0b00000001 & resp[1];
+ report->snrhint = 0x08 & resp[1];
+ report->snrlint = 0x04 & resp[1];
+ report->rssihint = 0x02 & resp[1];
+ report->rssilint = 0x01 & resp[1];
- report->bltf = 0b10000000 & resp[2];
- report->snr_ready = 0b00100000 & resp[2];
- report->rssiready = 0b00001000 & resp[2];
- report->afcrl = 0b00000010 & resp[2];
- report->valid = 0b00000001 & resp[2];
+ report->bltf = 0x80 & resp[2];
+ report->snr_ready = 0x20 & resp[2];
+ report->rssiready = 0x08 & resp[2];
+ report->afcrl = 0x02 & resp[2];
+ report->valid = 0x01 & resp[2];
- report->readfreq = be16_to_cpup((__be16 *)(resp + 3));
+ report->readfreq = get_unaligned_be16(resp + 3);
report->freqoff = resp[5];
report->rssi = resp[6];
report->snr = resp[7];
@@ -931,26 +933,26 @@ int si476x_core_cmd_fm_rds_status(struct si476x_core *core,
if (err < 0 || report == NULL)
return err;
- report->rdstpptyint = 0b00010000 & resp[1];
- report->rdspiint = 0b00001000 & resp[1];
- report->rdssyncint = 0b00000010 & resp[1];
- report->rdsfifoint = 0b00000001 & resp[1];
+ report->rdstpptyint = 0x10 & resp[1];
+ report->rdspiint = 0x08 & resp[1];
+ report->rdssyncint = 0x02 & resp[1];
+ report->rdsfifoint = 0x01 & resp[1];
- report->tpptyvalid = 0b00010000 & resp[2];
- report->pivalid = 0b00001000 & resp[2];
- report->rdssync = 0b00000010 & resp[2];
- report->rdsfifolost = 0b00000001 & resp[2];
+ report->tpptyvalid = 0x10 & resp[2];
+ report->pivalid = 0x08 & resp[2];
+ report->rdssync = 0x02 & resp[2];
+ report->rdsfifolost = 0x01 & resp[2];
- report->tp = 0b00100000 & resp[3];
- report->pty = 0b00011111 & resp[3];
+ report->tp = 0x20 & resp[3];
+ report->pty = 0x1f & resp[3];
- report->pi = be16_to_cpup((__be16 *)(resp + 4));
+ report->pi = get_unaligned_be16(resp + 4);
report->rdsfifoused = resp[6];
- report->ble[V4L2_RDS_BLOCK_A] = 0b11000000 & resp[7];
- report->ble[V4L2_RDS_BLOCK_B] = 0b00110000 & resp[7];
- report->ble[V4L2_RDS_BLOCK_C] = 0b00001100 & resp[7];
- report->ble[V4L2_RDS_BLOCK_D] = 0b00000011 & resp[7];
+ report->ble[V4L2_RDS_BLOCK_A] = 0xc0 & resp[7];
+ report->ble[V4L2_RDS_BLOCK_B] = 0x30 & resp[7];
+ report->ble[V4L2_RDS_BLOCK_C] = 0x0c & resp[7];
+ report->ble[V4L2_RDS_BLOCK_D] = 0x03 & resp[7];
report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A;
report->rds[V4L2_RDS_BLOCK_A].msb = resp[8];
@@ -991,9 +993,9 @@ int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core,
SI476X_DEFAULT_TIMEOUT);
if (!err) {
- report->expected = be16_to_cpup((__be16 *)(resp + 2));
- report->received = be16_to_cpup((__be16 *)(resp + 4));
- report->uncorrectable = be16_to_cpup((__be16 *)(resp + 6));
+ report->expected = get_unaligned_be16(resp + 2);
+ report->received = get_unaligned_be16(resp + 4);
+ report->uncorrectable = get_unaligned_be16(resp + 6);
}
return err;
@@ -1005,7 +1007,7 @@ int si476x_core_cmd_fm_phase_diversity(struct si476x_core *core,
{
u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP];
const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = {
- mode & 0b111,
+ mode & 0x07,
};
return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY,
@@ -1162,7 +1164,7 @@ static int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core,
const int am_freq = tuneargs->freq;
u8 resp[CMD_AM_TUNE_FREQ_NRESP];
const u8 args[CMD_AM_TUNE_FREQ_NARGS] = {
- (tuneargs->zifsr << 6) | (tuneargs->injside & 0b11),
+ (tuneargs->zifsr << 6) | (tuneargs->injside & 0x03),
msb(am_freq),
lsb(am_freq),
};
@@ -1197,20 +1199,20 @@ static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core,
if (err < 0 || report == NULL)
return err;
- report->multhint = 0b10000000 & resp[1];
- report->multlint = 0b01000000 & resp[1];
- report->snrhint = 0b00001000 & resp[1];
- report->snrlint = 0b00000100 & resp[1];
- report->rssihint = 0b00000010 & resp[1];
- report->rssilint = 0b00000001 & resp[1];
+ report->multhint = 0x80 & resp[1];
+ report->multlint = 0x40 & resp[1];
+ report->snrhint = 0x08 & resp[1];
+ report->snrlint = 0x04 & resp[1];
+ report->rssihint = 0x02 & resp[1];
+ report->rssilint = 0x01 & resp[1];
- report->bltf = 0b10000000 & resp[2];
- report->snr_ready = 0b00100000 & resp[2];
- report->rssiready = 0b00001000 & resp[2];
- report->afcrl = 0b00000010 & resp[2];
- report->valid = 0b00000001 & resp[2];
+ report->bltf = 0x80 & resp[2];
+ report->snr_ready = 0x20 & resp[2];
+ report->rssiready = 0x08 & resp[2];
+ report->afcrl = 0x02 & resp[2];
+ report->valid = 0x01 & resp[2];
- report->readfreq = be16_to_cpup((__be16 *)(resp + 3));
+ report->readfreq = get_unaligned_be16(resp + 3);
report->freqoff = resp[5];
report->rssi = resp[6];
report->snr = resp[7];
@@ -1218,7 +1220,7 @@ static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core,
report->hassi = resp[10];
report->mult = resp[11];
report->dev = resp[12];
- report->readantcap = be16_to_cpup((__be16 *)(resp + 13));
+ report->readantcap = get_unaligned_be16(resp + 13);
report->assi = resp[15];
report->usn = resp[16];
@@ -1251,20 +1253,20 @@ static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core,
if (err < 0 || report == NULL)
return err;
- report->multhint = 0b10000000 & resp[1];
- report->multlint = 0b01000000 & resp[1];
- report->snrhint = 0b00001000 & resp[1];
- report->snrlint = 0b00000100 & resp[1];
- report->rssihint = 0b00000010 & resp[1];
- report->rssilint = 0b00000001 & resp[1];
+ report->multhint = 0x80 & resp[1];
+ report->multlint = 0x40 & resp[1];
+ report->snrhint = 0x08 & resp[1];
+ report->snrlint = 0x04 & resp[1];
+ report->rssihint = 0x02 & resp[1];
+ report->rssilint = 0x01 & resp[1];
- report->bltf = 0b10000000 & resp[2];
- report->snr_ready = 0b00100000 & resp[2];
- report->rssiready = 0b00001000 & resp[2];
- report->afcrl = 0b00000010 & resp[2];
- report->valid = 0b00000001 & resp[2];
+ report->bltf = 0x80 & resp[2];
+ report->snr_ready = 0x20 & resp[2];
+ report->rssiready = 0x08 & resp[2];
+ report->afcrl = 0x02 & resp[2];
+ report->valid = 0x01 & resp[2];
- report->readfreq = be16_to_cpup((__be16 *)(resp + 3));
+ report->readfreq = get_unaligned_be16(resp + 3);
report->freqoff = resp[5];
report->rssi = resp[6];
report->snr = resp[7];
@@ -1272,7 +1274,7 @@ static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core,
report->hassi = resp[10];
report->mult = resp[11];
report->dev = resp[12];
- report->readantcap = be16_to_cpup((__be16 *)(resp + 13));
+ report->readantcap = get_unaligned_be16(resp + 13);
report->assi = resp[15];
report->usn = resp[16];
@@ -1306,21 +1308,21 @@ static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core,
if (err < 0 || report == NULL)
return err;
- report->multhint = 0b10000000 & resp[1];
- report->multlint = 0b01000000 & resp[1];
- report->snrhint = 0b00001000 & resp[1];
- report->snrlint = 0b00000100 & resp[1];
- report->rssihint = 0b00000010 & resp[1];
- report->rssilint = 0b00000001 & resp[1];
-
- report->bltf = 0b10000000 & resp[2];
- report->snr_ready = 0b00100000 & resp[2];
- report->rssiready = 0b00001000 & resp[2];
- report->injside = 0b00000100 & resp[2];
- report->afcrl = 0b00000010 & resp[2];
- report->valid = 0b00000001 & resp[2];
-
- report->readfreq = be16_to_cpup((__be16 *)(resp + 3));
+ report->multhint = 0x80 & resp[1];
+ report->multlint = 0x40 & resp[1];
+ report->snrhint = 0x08 & resp[1];
+ report->snrlint = 0x04 & resp[1];
+ report->rssihint = 0x02 & resp[1];
+ report->rssilint = 0x01 & resp[1];
+
+ report->bltf = 0x80 & resp[2];
+ report->snr_ready = 0x20 & resp[2];
+ report->rssiready = 0x08 & resp[2];
+ report->injside = 0x04 & resp[2];
+ report->afcrl = 0x02 & resp[2];
+ report->valid = 0x01 & resp[2];
+
+ report->readfreq = get_unaligned_be16(resp + 3);
report->freqoff = resp[5];
report->rssi = resp[6];
report->snr = resp[7];
@@ -1329,7 +1331,7 @@ static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core,
report->hassi = resp[10];
report->mult = resp[11];
report->dev = resp[12];
- report->readantcap = be16_to_cpup((__be16 *)(resp + 13));
+ report->readantcap = get_unaligned_be16(resp + 13);
report->assi = resp[15];
report->usn = resp[16];
@@ -1337,7 +1339,7 @@ static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core,
report->rdsdev = resp[18];
report->assidev = resp[19];
report->strongdev = resp[20];
- report->rdspi = be16_to_cpup((__be16 *)(resp + 21));
+ report->rdspi = get_unaligned_be16(resp + 21);
return err;
}
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index c09c28f..1abd5ad 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -154,11 +154,6 @@ static int ssc_probe(struct platform_device *pdev)
ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- dev_dbg(&pdev->dev, "no mmio resource defined\n");
- return -ENXIO;
- }
-
ssc->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(ssc->regs))
return PTR_ERR(ssc->regs);
diff --git a/drivers/misc/dummy-irq.c b/drivers/misc/dummy-irq.c
index 7014167..c37eeed 100644
--- a/drivers/misc/dummy-irq.c
+++ b/drivers/misc/dummy-irq.c
@@ -19,7 +19,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
-static int irq;
+static int irq = -1;
static irqreturn_t dummy_interrupt(int irq, void *dev_id)
{
@@ -36,6 +36,10 @@ static irqreturn_t dummy_interrupt(int irq, void *dev_id)
static int __init dummy_irq_init(void)
{
+ if (irq < 0) {
+ printk(KERN_ERR "dummy-irq: no IRQ given. Use irq=N\n");
+ return -EIO;
+ }
if (request_irq(irq, &dummy_interrupt, IRQF_SHARED, "dummy_irq", &irq)) {
printk(KERN_ERR "dummy-irq: cannot register IRQ %d\n", irq);
return -EIO;
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 1e935ea..9ecd49a 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -496,6 +496,8 @@ int mei_cl_disable_device(struct mei_cl_device *device)
}
}
+ device->event_cb = NULL;
+
mutex_unlock(&dev->device_lock);
if (!device->ops || !device->ops->disable)
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 713d89f..f580d30 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -197,6 +197,8 @@ void mei_stop(struct mei_device *dev)
{
dev_dbg(&dev->pdev->dev, "stopping the device.\n");
+ flush_scheduled_work();
+
mutex_lock(&dev->device_lock);
cancel_delayed_work(&dev->timer_work);
@@ -210,8 +212,6 @@ void mei_stop(struct mei_device *dev)
mutex_unlock(&dev->device_lock);
- flush_scheduled_work();
-
mei_watchdog_unregister(dev);
}
EXPORT_SYMBOL_GPL(mei_stop);
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 7c44c8d..053139f 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -489,11 +489,16 @@ static int mei_ioctl_connect_client(struct file *file,
/* find ME client we're trying to connect to */
i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
- if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
- cl->me_client_id = dev->me_clients[i].client_id;
- cl->state = MEI_FILE_CONNECTING;
+ if (i < 0 || dev->me_clients[i].props.fixed_address) {
+ dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
+ &data->in_client_uuid);
+ rets = -ENODEV;
+ goto end;
}
+ cl->me_client_id = dev->me_clients[i].client_id;
+ cl->state = MEI_FILE_CONNECTING;
+
dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
cl->me_client_id);
dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
@@ -527,11 +532,6 @@ static int mei_ioctl_connect_client(struct file *file,
goto end;
}
- if (cl->state != MEI_FILE_CONNECTING) {
- rets = -ENODEV;
- goto end;
- }
-
/* prepare the output buffer */
client = &data->out_client_properties;
@@ -543,7 +543,6 @@ static int mei_ioctl_connect_client(struct file *file,
rets = mei_cl_connect(cl, file);
end:
- dev_dbg(&dev->pdev->dev, "free connect cb memory.");
return rets;
}
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 3adf8a7..d0c6907 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -142,6 +142,8 @@ static void mei_nfc_free(struct mei_nfc_dev *ndev)
mei_cl_unlink(ndev->cl_info);
kfree(ndev->cl_info);
}
+
+ memset(ndev, 0, sizeof(struct mei_nfc_dev));
}
static int mei_nfc_build_bus_name(struct mei_nfc_dev *ndev)
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index a727464..0f26832 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -325,6 +325,7 @@ static int mei_me_pci_resume(struct device *device)
mutex_lock(&dev->device_lock);
dev->dev_state = MEI_DEV_POWER_UP;
+ mei_clear_interrupts(dev);
mei_reset(dev, 1);
mutex_unlock(&dev->device_lock);
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index 44d273c..0535d1e 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -172,6 +172,7 @@ static long gru_get_config_info(unsigned long arg)
nodesperblade = 2;
else
nodesperblade = 1;
+ memset(&info, 0, sizeof(info));
info.cpus = num_online_cpus();
info.nodes = num_online_nodes();
info.blades = info.nodes / nodesperblade;
diff --git a/drivers/misc/vmw_vmci/Kconfig b/drivers/misc/vmw_vmci/Kconfig
index ea98f7e..39c2eca 100644
--- a/drivers/misc/vmw_vmci/Kconfig
+++ b/drivers/misc/vmw_vmci/Kconfig
@@ -4,7 +4,7 @@
config VMWARE_VMCI
tristate "VMware VMCI Driver"
- depends on X86 && PCI && NET
+ depends on X86 && PCI
help
This is VMware's Virtual Machine Communication Interface. It enables
high-speed communication between host and guest in a virtual
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index d94245d..8ff2e5e 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -23,7 +23,7 @@
#include <linux/pagemap.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/socket.h>
+#include <linux/uio.h>
#include <linux/wait.h>
#include <linux/vmalloc.h>
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index e75774f..aca59d9 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -2230,10 +2230,15 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
mmc_free_host(slot->mmc);
}
-static bool atmci_filter(struct dma_chan *chan, void *slave)
+static bool atmci_filter(struct dma_chan *chan, void *pdata)
{
- struct mci_dma_data *sl = slave;
+ struct mci_platform_data *sl_pdata = pdata;
+ struct mci_dma_data *sl;
+ if (!sl_pdata)
+ return false;
+
+ sl = sl_pdata->dma_slave;
if (sl && find_slave_dev(sl) == chan->device->dev) {
chan->private = slave_data_ptr(sl);
return true;
@@ -2245,24 +2250,18 @@ static bool atmci_filter(struct dma_chan *chan, void *slave)
static bool atmci_configure_dma(struct atmel_mci *host)
{
struct mci_platform_data *pdata;
+ dma_cap_mask_t mask;
if (host == NULL)
return false;
pdata = host->pdev->dev.platform_data;
- if (!pdata)
- return false;
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
- if (pdata->dma_slave && find_slave_dev(pdata->dma_slave)) {
- dma_cap_mask_t mask;
-
- /* Try to grab a DMA channel */
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- host->dma.chan =
- dma_request_channel(mask, atmci_filter, pdata->dma_slave);
- }
+ host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata,
+ &host->pdev->dev, "rxtx");
if (!host->dma.chan) {
dev_warn(&host->pdev->dev, "no DMA channel available\n");
return false;
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 375c109..f4f3038 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1130,6 +1130,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct variant_data *variant = host->variant;
u32 pwr = 0;
unsigned long flags;
+ int ret;
pm_runtime_get_sync(mmc_dev(mmc));
@@ -1161,8 +1162,12 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
case MMC_POWER_ON:
if (!IS_ERR(mmc->supply.vqmmc) &&
- !regulator_is_enabled(mmc->supply.vqmmc))
- regulator_enable(mmc->supply.vqmmc);
+ !regulator_is_enabled(mmc->supply.vqmmc)) {
+ ret = regulator_enable(mmc->supply.vqmmc);
+ if (ret < 0)
+ dev_err(mmc_dev(mmc),
+ "failed to enable vqmmc regulator\n");
+ }
pwr |= MCI_PWR_ON;
break;
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 6e44025..eccedc7 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -161,6 +161,7 @@ struct omap_hsmmc_host {
*/
struct regulator *vcc;
struct regulator *vcc_aux;
+ int pbias_disable;
void __iomem *base;
resource_size_t mapbase;
spinlock_t irq_lock; /* Prevent races with irq handler */
@@ -255,11 +256,11 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
if (!host->vcc)
return 0;
/*
- * With DT, never turn OFF the regulator. This is because
+ * With DT, never turn OFF the regulator for MMC1. This is because
* the pbias cell programming support is still missing when
* booting with Device tree
*/
- if (dev->of_node && !vdd)
+ if (host->pbias_disable && !vdd)
return 0;
if (mmc_slot(host).before_set_reg)
@@ -1520,10 +1521,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
(ios->vdd == DUAL_VOLT_OCR_BIT) &&
/*
* With pbias cell programming missing, this
- * can't be allowed when booting with device
+ * can't be allowed on MMC1 when booting with device
* tree.
*/
- !host->dev->of_node) {
+ !host->pbias_disable) {
/*
* The mmc_select_voltage fn of the core does
* not seem to set the power_mode to
@@ -1871,6 +1872,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_context_save(host);
+ /* This can be removed once we support PBIAS with DT */
+ if (host->dev->of_node && host->mapbase == 0x4809c000)
+ host->pbias_disable = 1;
+
host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
/*
* MMC can still work without debounce clock.
@@ -1906,33 +1911,41 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_conf_bus_power(host);
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (!res) {
- dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
- ret = -ENXIO;
- goto err_irq;
- }
- tx_req = res->start;
+ if (!pdev->dev.of_node) {
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
+ if (!res) {
+ dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
+ ret = -ENXIO;
+ goto err_irq;
+ }
+ tx_req = res->start;
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (!res) {
- dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
- ret = -ENXIO;
- goto err_irq;
+ res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
+ if (!res) {
+ dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
+ ret = -ENXIO;
+ goto err_irq;
+ }
+ rx_req = res->start;
}
- rx_req = res->start;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- host->rx_chan = dma_request_channel(mask, omap_dma_filter_fn, &rx_req);
+ host->rx_chan =
+ dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
+ &rx_req, &pdev->dev, "rx");
+
if (!host->rx_chan) {
dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel %u\n", rx_req);
ret = -ENXIO;
goto err_irq;
}
- host->tx_chan = dma_request_channel(mask, omap_dma_filter_fn, &tx_req);
+ host->tx_chan =
+ dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
+ &tx_req, &pdev->dev, "tx");
+
if (!host->tx_chan) {
dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel %u\n", tx_req);
ret = -ENXIO;
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 7bcf74b..706d9cb 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -87,6 +87,12 @@ static const struct sdhci_ops sdhci_acpi_ops_dflt = {
.enable_dma = sdhci_acpi_enable_dma,
};
+static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
+ .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+ .caps2 = MMC_CAP2_HC_ERASE_SZ,
+ .flags = SDHCI_ACPI_RUNTIME_PM,
+};
+
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
.caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
@@ -94,23 +100,67 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
.pm_caps = MMC_PM_KEEP_POWER,
};
+static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
+};
+
+struct sdhci_acpi_uid_slot {
+ const char *hid;
+ const char *uid;
+ const struct sdhci_acpi_slot *slot;
+};
+
+static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
+ { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
+ { "80860F14" , "3" , &sdhci_acpi_slot_int_sd },
+ { "INT33BB" , "2" , &sdhci_acpi_slot_int_sdio },
+ { "INT33C6" , NULL, &sdhci_acpi_slot_int_sdio },
+ { "PNP0D40" },
+ { },
+};
+
static const struct acpi_device_id sdhci_acpi_ids[] = {
- { "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio },
- { "PNP0D40" },
+ { "80860F14" },
+ { "INT33BB" },
+ { "INT33C6" },
+ { "PNP0D40" },
{ },
};
MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
-static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid)
+static const struct sdhci_acpi_slot *sdhci_acpi_get_slot_by_ids(const char *hid,
+ const char *uid)
{
- const struct acpi_device_id *id;
-
- for (id = sdhci_acpi_ids; id->id[0]; id++)
- if (!strcmp(id->id, hid))
- return (const struct sdhci_acpi_slot *)id->driver_data;
+ const struct sdhci_acpi_uid_slot *u;
+
+ for (u = sdhci_acpi_uids; u->hid; u++) {
+ if (strcmp(u->hid, hid))
+ continue;
+ if (!u->uid)
+ return u->slot;
+ if (uid && !strcmp(u->uid, uid))
+ return u->slot;
+ }
return NULL;
}
+static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
+ const char *hid)
+{
+ const struct sdhci_acpi_slot *slot;
+ struct acpi_device_info *info;
+ const char *uid = NULL;
+ acpi_status status;
+
+ status = acpi_get_object_info(handle, &info);
+ if (!ACPI_FAILURE(status) && (info->valid & ACPI_VALID_UID))
+ uid = info->unique_id.string;
+
+ slot = sdhci_acpi_get_slot_by_ids(hid, uid);
+
+ kfree(info);
+ return slot;
+}
+
static int sdhci_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -148,7 +198,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
c = sdhci_priv(host);
c->host = host;
- c->slot = sdhci_acpi_get_slot(hid);
+ c->slot = sdhci_acpi_get_slot(handle, hid);
c->pdev = pdev;
c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM);
@@ -202,6 +252,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
goto err_free;
if (c->use_runtime_pm) {
+ pm_runtime_set_active(dev);
pm_suspend_ignore_children(dev, 1);
pm_runtime_set_autosuspend_delay(dev, 50);
pm_runtime_use_autosuspend(dev);
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 67d6dde..d5f0d59 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -85,6 +85,12 @@ struct pltfm_imx_data {
struct clk *clk_ipg;
struct clk *clk_ahb;
struct clk *clk_per;
+ enum {
+ NO_CMD_PENDING, /* no multiblock command pending*/
+ MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
+ WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
+ } multiblock_status;
+
};
static struct platform_device_id imx_esdhc_devtype[] = {
@@ -154,6 +160,8 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i
static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct pltfm_imx_data *imx_data = pltfm_host->priv;
u32 val = readl(host->ioaddr + reg);
if (unlikely(reg == SDHCI_CAPABILITIES)) {
@@ -175,6 +183,18 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
val &= ~ESDHC_INT_VENDOR_SPEC_DMA_ERR;
val |= SDHCI_INT_ADMA_ERROR;
}
+
+ /*
+ * mask off the interrupt we get in response to the manually
+ * sent CMD12
+ */
+ if ((imx_data->multiblock_status == WAIT_FOR_INT) &&
+ ((val & SDHCI_INT_RESPONSE) == SDHCI_INT_RESPONSE)) {
+ val &= ~SDHCI_INT_RESPONSE;
+ writel(SDHCI_INT_RESPONSE, host->ioaddr +
+ SDHCI_INT_STATUS);
+ imx_data->multiblock_status = NO_CMD_PENDING;
+ }
}
return val;
@@ -211,6 +231,15 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
v = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
v &= ~ESDHC_VENDOR_SPEC_SDIO_QUIRK;
writel(v, host->ioaddr + ESDHC_VENDOR_SPEC);
+
+ if (imx_data->multiblock_status == MULTIBLK_IN_PROCESS)
+ {
+ /* send a manual CMD12 with RESPTYP=none */
+ data = MMC_STOP_TRANSMISSION << 24 |
+ SDHCI_CMD_ABORTCMD << 16;
+ writel(data, host->ioaddr + SDHCI_TRANSFER_MODE);
+ imx_data->multiblock_status = WAIT_FOR_INT;
+ }
}
if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
@@ -277,11 +306,13 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
}
return;
case SDHCI_COMMAND:
- if ((host->cmd->opcode == MMC_STOP_TRANSMISSION ||
- host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
- (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
+ if (host->cmd->opcode == MMC_STOP_TRANSMISSION)
val |= SDHCI_CMD_ABORTCMD;
+ if ((host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
+ (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
+ imx_data->multiblock_status = MULTIBLK_IN_PROCESS;
+
if (is_imx6q_usdhc(imx_data))
writel(val << 16,
host->ioaddr + SDHCI_TRANSFER_MODE);
@@ -324,8 +355,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
/*
* Do not touch buswidth bits here. This is done in
* esdhc_pltfm_bus_width.
+ * Do not touch the D3CD bit either which is used for the
+ * SDIO interrupt errata workaround.
*/
- mask = 0xffff & ~ESDHC_CTRL_BUSWIDTH_MASK;
+ mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD);
esdhc_clrset_le(host, mask, new_val, reg);
return;
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 0012d3f..701d06d 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -33,6 +33,9 @@
*/
#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a
+#define PCI_DEVICE_ID_INTEL_BYT_EMMC 0x0f14
+#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15
+#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16
/*
* PCI registers
@@ -304,6 +307,33 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
.probe_slot = pch_hc_probe_slot,
};
+static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
+{
+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
+ slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
+ return 0;
+}
+
+static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
+{
+ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
+ return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
+ .allow_runtime_pm = true,
+ .probe_slot = byt_emmc_probe_slot,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
+ .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
+ .allow_runtime_pm = true,
+ .probe_slot = byt_sdio_probe_slot,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
+};
+
/* O2Micro extra registers */
#define O2_SD_LOCK_WP 0xD3
#define O2_SD_MULTI_VCC3V 0xEE
@@ -856,6 +886,30 @@ static const struct pci_device_id pci_ids[] = {
},
{
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_BYT_EMMC,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_BYT_SDIO,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_BYT_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
+ },
+
+ {
.vendor = PCI_VENDOR_ID_O2,
.device = PCI_DEVICE_ID_O2_8120,
.subvendor = PCI_ANY_ID,
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
index a94facb..fd1df5e 100644
--- a/drivers/mtd/nand/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/lpc32xx_mlc.c
@@ -672,11 +672,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
}
rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (rc == NULL) {
- dev_err(&pdev->dev, "No memory resource found for device!\r\n");
- return -ENXIO;
- }
-
host->io_base = devm_ioremap_resource(&pdev->dev, rc);
if (IS_ERR(host->io_base))
return PTR_ERR(host->io_base);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 3835321..00aba08 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -25,6 +25,9 @@ menuconfig NETDEVICES
# that for each of the symbols.
if NETDEVICES
+config MII
+ tristate
+
config NET_CORE
default y
bool "Network core driver support"
@@ -100,13 +103,6 @@ config NET_FC
adaptor below. You also should have said Y to "SCSI support" and
"SCSI generic support".
-config MII
- tristate "Generic Media Independent Interface device support"
- help
- Most ethernet controllers have MII transceiver either as an external
- or internal device. It is safe to say Y or M here even if your
- ethernet card lacks MII.
-
config IFB
tristate "Intermediate Functional Block support"
depends on NET_CLS_ACT
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index fc58d11..390061d 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2360,14 +2360,15 @@ int bond_3ad_set_carrier(struct bonding *bond)
}
/**
- * bond_3ad_get_active_agg_info - get information of the active aggregator
+ * __bond_3ad_get_active_agg_info - get information of the active aggregator
* @bond: bonding struct to work on
* @ad_info: ad_info struct to fill with the bond's info
*
* Returns: 0 on success
* < 0 on error
*/
-int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
+int __bond_3ad_get_active_agg_info(struct bonding *bond,
+ struct ad_info *ad_info)
{
struct aggregator *aggregator = NULL;
struct port *port;
@@ -2391,6 +2392,18 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
return -1;
}
+/* Wrapper used to hold bond->lock so no slave manipulation can occur */
+int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
+{
+ int ret;
+
+ read_lock(&bond->lock);
+ ret = __bond_3ad_get_active_agg_info(bond, ad_info);
+ read_unlock(&bond->lock);
+
+ return ret;
+}
+
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
{
struct slave *slave, *start_at;
@@ -2402,8 +2415,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
struct ad_info ad_info;
int res = 1;
- if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
- pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n",
+ if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
+ pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
dev->name);
goto out;
}
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 0cfaa4a..5d91ad0 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -273,6 +273,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave);
void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
+int __bond_3ad_get_active_agg_info(struct bonding *bond,
+ struct ad_info *ad_info);
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave);
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index e02cc26..4ea8ed1 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1056,7 +1056,7 @@ static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[])
*
*/
-static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2)
+static void alb_swap_mac_addr(struct slave *slave1, struct slave *slave2)
{
u8 tmp_mac_addr[ETH_ALEN];
@@ -1129,6 +1129,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
{
int perm_curr_diff;
int perm_bond_diff;
+ struct slave *found_slave;
perm_curr_diff = !ether_addr_equal_64bits(slave->perm_hwaddr,
slave->dev->dev_addr);
@@ -1136,21 +1137,12 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
bond->dev->dev_addr);
if (perm_curr_diff && perm_bond_diff) {
- struct slave *tmp_slave;
- int i, found = 0;
-
- bond_for_each_slave(bond, tmp_slave, i) {
- if (ether_addr_equal_64bits(slave->perm_hwaddr,
- tmp_slave->dev->dev_addr)) {
- found = 1;
- break;
- }
- }
+ found_slave = bond_slave_has_mac(bond, slave->perm_hwaddr);
- if (found) {
+ if (found_slave) {
/* locking: needs RTNL and nothing else */
- alb_swap_mac_addr(bond, slave, tmp_slave);
- alb_fasten_mac_swap(bond, slave, tmp_slave);
+ alb_swap_mac_addr(slave, found_slave);
+ alb_fasten_mac_swap(bond, slave, found_slave);
}
}
}
@@ -1175,16 +1167,13 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla
* @slave.
*
* assumption: this function is called before @slave is attached to the
- * bond slave list.
- *
- * caller must hold the bond lock for write since the mac addresses are compared
- * and may be swapped.
+ * bond slave list.
*/
static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave)
{
- struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave;
+ struct slave *tmp_slave1, *free_mac_slave = NULL;
struct slave *has_bond_addr = bond->curr_active_slave;
- int i, j, found = 0;
+ int i;
if (bond->slave_cnt == 0) {
/* this is the first slave */
@@ -1196,15 +1185,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
* slaves in the bond.
*/
if (!ether_addr_equal_64bits(slave->perm_hwaddr, bond->dev->dev_addr)) {
- bond_for_each_slave(bond, tmp_slave1, i) {
- if (ether_addr_equal_64bits(tmp_slave1->dev->dev_addr,
- slave->dev->dev_addr)) {
- found = 1;
- break;
- }
- }
-
- if (!found)
+ if (!bond_slave_has_mac(bond, slave->dev->dev_addr))
return 0;
/* Try setting slave mac to bond address and fall-through
@@ -1215,19 +1196,8 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
/* The slave's address is equal to the address of the bond.
* Search for a spare address in the bond for this slave.
*/
- free_mac_slave = NULL;
-
bond_for_each_slave(bond, tmp_slave1, i) {
- found = 0;
- bond_for_each_slave(bond, tmp_slave2, j) {
- if (ether_addr_equal_64bits(tmp_slave1->perm_hwaddr,
- tmp_slave2->dev->dev_addr)) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
+ if (!bond_slave_has_mac(bond, tmp_slave1->perm_hwaddr)) {
/* no slave has tmp_slave1's perm addr
* as its curr addr
*/
@@ -1607,15 +1577,7 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
return res;
}
- /* caller must hold the bond lock for write since the mac addresses
- * are compared and may be swapped.
- */
- read_lock(&bond->lock);
-
res = alb_handle_addr_collision_on_attach(bond, slave);
-
- read_unlock(&bond->lock);
-
if (res) {
return res;
}
@@ -1698,7 +1660,6 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
__acquires(&bond->curr_slave_lock)
{
struct slave *swap_slave;
- int i;
if (bond->curr_active_slave == new_slave) {
return;
@@ -1720,17 +1681,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
/* set the new curr_active_slave to the bonds mac address
* i.e. swap mac addresses of old curr_active_slave and new curr_active_slave
*/
- if (!swap_slave) {
- struct slave *tmp_slave;
- /* find slave that is holding the bond's mac address */
- bond_for_each_slave(bond, tmp_slave, i) {
- if (ether_addr_equal_64bits(tmp_slave->dev->dev_addr,
- bond->dev->dev_addr)) {
- swap_slave = tmp_slave;
- break;
- }
- }
- }
+ if (!swap_slave)
+ swap_slave = bond_slave_has_mac(bond, bond->dev->dev_addr);
/*
* Arrange for swap_slave and new_slave to temporarily be
@@ -1750,16 +1702,12 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
/* curr_active_slave must be set before calling alb_swap_mac_addr */
if (swap_slave) {
/* swap mac address */
- alb_swap_mac_addr(bond, swap_slave, new_slave);
- } else {
- /* set the new_slave to the bond mac address */
- alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr);
- }
-
- if (swap_slave) {
+ alb_swap_mac_addr(swap_slave, new_slave);
alb_fasten_mac_swap(bond, swap_slave, new_slave);
read_lock(&bond->lock);
} else {
+ /* set the new_slave to the bond mac address */
+ alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr);
read_lock(&bond->lock);
alb_send_learning_packets(new_slave, bond->dev->dev_addr);
}
@@ -1776,9 +1724,8 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
{
struct bonding *bond = netdev_priv(bond_dev);
struct sockaddr *sa = addr;
- struct slave *slave, *swap_slave;
+ struct slave *swap_slave;
int res;
- int i;
if (!is_valid_ether_addr(sa->sa_data)) {
return -EADDRNOTAVAIL;
@@ -1799,18 +1746,10 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
return 0;
}
- swap_slave = NULL;
-
- bond_for_each_slave(bond, slave, i) {
- if (ether_addr_equal_64bits(slave->dev->dev_addr,
- bond_dev->dev_addr)) {
- swap_slave = slave;
- break;
- }
- }
+ swap_slave = bond_slave_has_mac(bond, bond_dev->dev_addr);
if (swap_slave) {
- alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave);
+ alb_swap_mac_addr(swap_slave, bond->curr_active_slave);
alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave);
} else {
alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index d0aade0..3b31c19 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -706,45 +706,6 @@ static int bond_set_allmulti(struct bonding *bond, int inc)
return err;
}
-/*
- * Add a Multicast address to slaves
- * according to mode
- */
-static void bond_mc_add(struct bonding *bond, void *addr)
-{
- if (USES_PRIMARY(bond->params.mode)) {
- /* write lock already acquired */
- if (bond->curr_active_slave)
- dev_mc_add(bond->curr_active_slave->dev, addr);
- } else {
- struct slave *slave;
- int i;
-
- bond_for_each_slave(bond, slave, i)
- dev_mc_add(slave->dev, addr);
- }
-}
-
-/*
- * Remove a multicast address from slave
- * according to mode
- */
-static void bond_mc_del(struct bonding *bond, void *addr)
-{
- if (USES_PRIMARY(bond->params.mode)) {
- /* write lock already acquired */
- if (bond->curr_active_slave)
- dev_mc_del(bond->curr_active_slave->dev, addr);
- } else {
- struct slave *slave;
- int i;
- bond_for_each_slave(bond, slave, i) {
- dev_mc_del(slave->dev, addr);
- }
- }
-}
-
-
static void __bond_resend_igmp_join_requests(struct net_device *dev)
{
struct in_device *in_dev;
@@ -764,8 +725,8 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
struct net_device *bond_dev, *vlan_dev, *upper_dev;
struct vlan_entry *vlan;
- rcu_read_lock();
read_lock(&bond->lock);
+ rcu_read_lock();
bond_dev = bond->dev;
@@ -787,12 +748,19 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
if (vlan_dev)
__bond_resend_igmp_join_requests(vlan_dev);
}
+ rcu_read_unlock();
- if (--bond->igmp_retrans > 0)
+ /* We use curr_slave_lock to protect against concurrent access to
+ * igmp_retrans from multiple running instances of this function and
+ * bond_change_active_slave
+ */
+ write_lock_bh(&bond->curr_slave_lock);
+ if (bond->igmp_retrans > 1) {
+ bond->igmp_retrans--;
queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
-
+ }
+ write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
- rcu_read_unlock();
}
static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
@@ -803,17 +771,15 @@ static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
bond_resend_igmp_join_requests(bond);
}
-/*
- * flush all members of flush->mc_list from device dev->mc_list
+/* Flush bond's hardware addresses from slave
*/
-static void bond_mc_list_flush(struct net_device *bond_dev,
+static void bond_hw_addr_flush(struct net_device *bond_dev,
struct net_device *slave_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct netdev_hw_addr *ha;
- netdev_for_each_mc_addr(ha, bond_dev)
- dev_mc_del(slave_dev, ha->addr);
+ dev_uc_unsync(slave_dev, bond_dev);
+ dev_mc_unsync(slave_dev, bond_dev);
if (bond->params.mode == BOND_MODE_8023AD) {
/* del lacpdu mc addr from mc list */
@@ -825,22 +791,14 @@ static void bond_mc_list_flush(struct net_device *bond_dev,
/*--------------------------- Active slave change ---------------------------*/
-/*
- * Update the mc list and multicast-related flags for the new and
- * old active slaves (if any) according to the multicast mode, and
- * promiscuous flags unconditionally.
+/* Update the hardware address list and promisc/allmulti for the new and
+ * old active slaves (if any). Modes that are !USES_PRIMARY keep all
+ * slaves up date at all times; only the USES_PRIMARY modes need to call
+ * this function to swap these settings during a failover.
*/
-static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
- struct slave *old_active)
+static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
+ struct slave *old_active)
{
- struct netdev_hw_addr *ha;
-
- if (!USES_PRIMARY(bond->params.mode))
- /* nothing to do - mc list is already up-to-date on
- * all slaves
- */
- return;
-
if (old_active) {
if (bond->dev->flags & IFF_PROMISC)
dev_set_promiscuity(old_active->dev, -1);
@@ -848,10 +806,7 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
if (bond->dev->flags & IFF_ALLMULTI)
dev_set_allmulti(old_active->dev, -1);
- netif_addr_lock_bh(bond->dev);
- netdev_for_each_mc_addr(ha, bond->dev)
- dev_mc_del(old_active->dev, ha->addr);
- netif_addr_unlock_bh(bond->dev);
+ bond_hw_addr_flush(bond->dev, old_active->dev);
}
if (new_active) {
@@ -863,8 +818,8 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active,
dev_set_allmulti(new_active->dev, 1);
netif_addr_lock_bh(bond->dev);
- netdev_for_each_mc_addr(ha, bond->dev)
- dev_mc_add(new_active->dev, ha->addr);
+ dev_uc_sync(new_active->dev, bond->dev);
+ dev_mc_sync(new_active->dev, bond->dev);
netif_addr_unlock_bh(bond->dev);
}
}
@@ -1083,7 +1038,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
}
if (USES_PRIMARY(bond->params.mode))
- bond_mc_swap(bond, new_active, old_active);
+ bond_hw_addr_swap(bond, new_active, old_active);
if (bond_is_lb(bond)) {
bond_alb_handle_active_change(bond, new_active);
@@ -1362,6 +1317,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
slave->dev->features,
mask);
}
+ features = netdev_add_tso_features(features, mask);
out:
read_unlock(&bond->lock);
@@ -1525,7 +1481,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
struct bonding *bond = netdev_priv(bond_dev);
const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
struct slave *new_slave = NULL;
- struct netdev_hw_addr *ha;
struct sockaddr addr;
int link_reporting;
int res = 0;
@@ -1705,10 +1660,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_close;
}
- /* If the mode USES_PRIMARY, then the new slave gets the
- * master's promisc (and mc) settings only if it becomes the
- * curr_active_slave, and that is taken care of later when calling
- * bond_change_active()
+ /* If the mode USES_PRIMARY, then the following is handled by
+ * bond_change_active_slave().
*/
if (!USES_PRIMARY(bond->params.mode)) {
/* set promiscuity level to new slave */
@@ -1726,9 +1679,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
netif_addr_lock_bh(bond_dev);
- /* upload master's mc_list to new slave */
- netdev_for_each_mc_addr(ha, bond_dev)
- dev_mc_add(slave_dev, ha->addr);
+
+ dev_mc_sync_multiple(slave_dev, bond_dev);
+ dev_uc_sync_multiple(slave_dev, bond_dev);
+
netif_addr_unlock_bh(bond_dev);
}
@@ -1907,11 +1861,9 @@ err_dest_symlinks:
bond_destroy_slave_symlinks(bond_dev, slave_dev);
err_detach:
- if (!USES_PRIMARY(bond->params.mode)) {
- netif_addr_lock_bh(bond_dev);
- bond_mc_list_flush(bond_dev, slave_dev);
- netif_addr_unlock_bh(bond_dev);
- }
+ if (!USES_PRIMARY(bond->params.mode))
+ bond_hw_addr_flush(bond_dev, slave_dev);
+
bond_del_vlans_from_slave(bond, slave_dev);
write_lock_bh(&bond->lock);
bond_detach_slave(bond, new_slave);
@@ -1956,6 +1908,10 @@ err_free:
err_undo_flags:
bond_compute_features(bond);
+ /* Enslave of first slave has failed and we need to fix master's mac */
+ if (bond->slave_cnt == 0 &&
+ ether_addr_equal(bond_dev->dev_addr, slave_dev->dev_addr))
+ eth_hw_addr_random(bond_dev);
return res;
}
@@ -2106,9 +2062,8 @@ static int __bond_release_one(struct net_device *bond_dev,
bond_del_vlans_from_slave(bond, slave_dev);
- /* If the mode USES_PRIMARY, then we should only remove its
- * promisc and mc settings if it was the curr_active_slave, but that was
- * already taken care of above when we detached the slave
+ /* If the mode USES_PRIMARY, then this cases was handled above by
+ * bond_change_active_slave(..., NULL)
*/
if (!USES_PRIMARY(bond->params.mode)) {
/* unset promiscuity level from slave */
@@ -2119,10 +2074,7 @@ static int __bond_release_one(struct net_device *bond_dev,
if (bond_dev->flags & IFF_ALLMULTI)
dev_set_allmulti(slave_dev, -1);
- /* flush master's mc_list from slave */
- netif_addr_lock_bh(bond_dev);
- bond_mc_list_flush(bond_dev, slave_dev);
- netif_addr_unlock_bh(bond_dev);
+ bond_hw_addr_flush(bond_dev, slave_dev);
}
bond_upper_dev_unlink(bond_dev, slave_dev);
@@ -2555,8 +2507,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
{
struct sk_buff *skb;
- pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op,
- slave_dev->name, dest_ip, src_ip, vlan_id);
+ pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n", arp_op,
+ slave_dev->name, &dest_ip, &src_ip, vlan_id);
skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
NULL, slave_dev->dev_addr, NULL);
@@ -2588,7 +2540,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
__be32 addr;
if (!targets[i])
break;
- pr_debug("basa: target %x\n", targets[i]);
+ pr_debug("basa: target %pI4\n", &targets[i]);
if (!bond_vlan_used(bond)) {
pr_debug("basa: empty vlan: arp_send\n");
addr = bond_confirm_addr(bond->dev, targets[i], 0);
@@ -3276,7 +3228,7 @@ static int bond_slave_netdev_event(unsigned long event,
static int bond_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct net_device *event_dev = (struct net_device *)ptr;
+ struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
pr_debug("event_dev: %s, event: %lx\n",
event_dev ? event_dev->name : "None",
@@ -3659,19 +3611,6 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd
return res;
}
-static bool bond_addr_in_mc_list(unsigned char *addr,
- struct netdev_hw_addr_list *list,
- int addrlen)
-{
- struct netdev_hw_addr *ha;
-
- netdev_hw_addr_list_for_each(ha, list)
- if (!memcmp(ha->addr, addr, addrlen))
- return true;
-
- return false;
-}
-
static void bond_change_rx_flags(struct net_device *bond_dev, int change)
{
struct bonding *bond = netdev_priv(bond_dev);
@@ -3685,35 +3624,29 @@ static void bond_change_rx_flags(struct net_device *bond_dev, int change)
bond_dev->flags & IFF_ALLMULTI ? 1 : -1);
}
-static void bond_set_multicast_list(struct net_device *bond_dev)
+static void bond_set_rx_mode(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct netdev_hw_addr *ha;
- bool found;
+ struct slave *slave;
+ int i;
read_lock(&bond->lock);
- /* looking for addresses to add to slaves' mc list */
- netdev_for_each_mc_addr(ha, bond_dev) {
- found = bond_addr_in_mc_list(ha->addr, &bond->mc_list,
- bond_dev->addr_len);
- if (!found)
- bond_mc_add(bond, ha->addr);
- }
-
- /* looking for addresses to delete from slaves' list */
- netdev_hw_addr_list_for_each(ha, &bond->mc_list) {
- found = bond_addr_in_mc_list(ha->addr, &bond_dev->mc,
- bond_dev->addr_len);
- if (!found)
- bond_mc_del(bond, ha->addr);
+ if (USES_PRIMARY(bond->params.mode)) {
+ read_lock(&bond->curr_slave_lock);
+ slave = bond->curr_active_slave;
+ if (slave) {
+ dev_uc_sync(slave->dev, bond_dev);
+ dev_mc_sync(slave->dev, bond_dev);
+ }
+ read_unlock(&bond->curr_slave_lock);
+ } else {
+ bond_for_each_slave(bond, slave, i) {
+ dev_uc_sync_multiple(slave->dev, bond_dev);
+ dev_mc_sync_multiple(slave->dev, bond_dev);
+ }
}
- /* save master's multicast list */
- __hw_addr_flush(&bond->mc_list);
- __hw_addr_add_multiple(&bond->mc_list, &bond_dev->mc,
- bond_dev->addr_len, NETDEV_HW_ADDR_T_MULTICAST);
-
read_unlock(&bond->lock);
}
@@ -3858,11 +3791,10 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
pr_debug("bond=%p, name=%s\n",
bond, bond_dev ? bond_dev->name : "None");
- /*
- * If fail_over_mac is set to active, do nothing and return
- * success. Returning an error causes ifenslave to fail.
+ /* If fail_over_mac is enabled, do nothing and return success.
+ * Returning an error causes ifenslave to fail.
*/
- if (bond->params.fail_over_mac == BOND_FOM_ACTIVE)
+ if (bond->params.fail_over_mac)
return 0;
if (!is_valid_ether_addr(sa->sa_data))
@@ -4320,7 +4252,7 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_get_stats64 = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl,
.ndo_change_rx_flags = bond_change_rx_flags,
- .ndo_set_rx_mode = bond_set_multicast_list,
+ .ndo_set_rx_mode = bond_set_rx_mode,
.ndo_change_mtu = bond_change_mtu,
.ndo_set_mac_address = bond_set_mac_address,
.ndo_neigh_setup = bond_neigh_setup,
@@ -4425,8 +4357,6 @@ static void bond_uninit(struct net_device *bond_dev)
bond_debug_unregister(bond);
- __hw_addr_flush(&bond->mc_list);
-
list_for_each_entry_safe(vlan, tmp, &bond->vlan_list, vlan_list) {
list_del(&vlan->vlan_list);
kfree(vlan);
@@ -4470,7 +4400,7 @@ int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
static int bond_check_params(struct bond_params *params)
{
- int arp_validate_value, fail_over_mac_value, primary_reselect_value;
+ int arp_validate_value, fail_over_mac_value, primary_reselect_value, i;
/*
* Convert string parameters.
@@ -4650,19 +4580,18 @@ static int bond_check_params(struct bond_params *params)
arp_interval = BOND_LINK_ARP_INTERV;
}
- for (arp_ip_count = 0;
- (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[arp_ip_count];
- arp_ip_count++) {
+ for (arp_ip_count = 0, i = 0;
+ (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) {
/* not complete check, but should be good enough to
catch mistakes */
- __be32 ip = in_aton(arp_ip_target[arp_ip_count]);
- if (!isdigit(arp_ip_target[arp_ip_count][0]) ||
- ip == 0 || ip == htonl(INADDR_BROADCAST)) {
+ __be32 ip = in_aton(arp_ip_target[i]);
+ if (!isdigit(arp_ip_target[i][0]) || ip == 0 ||
+ ip == htonl(INADDR_BROADCAST)) {
pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n",
- arp_ip_target[arp_ip_count]);
+ arp_ip_target[i]);
arp_interval = 0;
} else {
- arp_target[arp_ip_count] = ip;
+ arp_target[arp_ip_count++] = ip;
}
}
@@ -4696,8 +4625,6 @@ static int bond_check_params(struct bond_params *params)
if (miimon) {
pr_info("MII link monitoring set to %d ms\n", miimon);
} else if (arp_interval) {
- int i;
-
pr_info("ARP monitoring set to %d ms, validate %s, with %d target(s):",
arp_interval,
arp_validate_tbl[arp_validate_value].modename,
@@ -4840,7 +4767,6 @@ static int bond_init(struct net_device *bond_dev)
bond->dev_addr_from_first = true;
}
- __hw_addr_init(&bond->mc_list);
return 0;
}
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index 94d06f1..4060d41 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -130,7 +130,7 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf(seq, "Aggregator selection policy (ad_select): %s\n",
ad_select_tbl[bond->params.ad_select].modename);
- if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
+ if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
seq_printf(seq, "bond %s has no active aggregator\n",
bond->dev->name);
} else {
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ea7a388..f8bee4c 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -231,8 +231,7 @@ static ssize_t bonding_show_slaves(struct device *d,
}
/*
- * Set the slaves in the current bond. The bond interface must be
- * up for this to succeed.
+ * Set the slaves in the current bond.
* This is supposed to be only thin wrapper for bond_enslave and bond_release.
* All hard work should be done there.
*/
@@ -316,6 +315,9 @@ static ssize_t bonding_store_mode(struct device *d,
int new_value, ret = count;
struct bonding *bond = to_bond(d);
+ if (!rtnl_trylock())
+ return restart_syscall();
+
if (bond->dev->flags & IFF_UP) {
pr_err("unable to update mode of %s because interface is up.\n",
bond->dev->name);
@@ -352,6 +354,7 @@ static ssize_t bonding_store_mode(struct device *d,
bond->dev->name, bond_mode_tbl[new_value].modename,
new_value);
out:
+ rtnl_unlock();
return ret;
}
static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
@@ -359,7 +362,6 @@ static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
/*
* Show and set the bonding transmit hash method.
- * The bond interface must be down to change the xmit hash policy.
*/
static ssize_t bonding_show_xmit_hash(struct device *d,
struct device_attribute *attr,
@@ -379,20 +381,12 @@ static ssize_t bonding_store_xmit_hash(struct device *d,
int new_value, ret = count;
struct bonding *bond = to_bond(d);
- if (bond->dev->flags & IFF_UP) {
- pr_err("%s: Interface is up. Unable to update xmit policy.\n",
- bond->dev->name);
- ret = -EPERM;
- goto out;
- }
-
new_value = bond_parse_parm(buf, xmit_hashtype_tbl);
if (new_value < 0) {
pr_err("%s: Ignoring invalid xmit hash policy value %.*s.\n",
bond->dev->name,
(int)strlen(buf) - 1, buf);
ret = -EINVAL;
- goto out;
} else {
bond->params.xmit_policy = new_value;
bond_set_mode_ops(bond, bond->params.mode);
@@ -400,7 +394,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d,
bond->dev->name,
xmit_hashtype_tbl[new_value].modename, new_value);
}
-out:
+
return ret;
}
static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR,
@@ -1315,7 +1309,6 @@ static ssize_t bonding_show_mii_status(struct device *d,
}
static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
-
/*
* Show current 802.3ad aggregator ID.
*/
@@ -1329,7 +1322,7 @@ static ssize_t bonding_show_ad_aggregator(struct device *d,
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
- (bond_3ad_get_active_agg_info(bond, &ad_info))
+ bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.aggregator_id);
}
@@ -1351,7 +1344,7 @@ static ssize_t bonding_show_ad_num_ports(struct device *d,
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
- (bond_3ad_get_active_agg_info(bond, &ad_info))
+ bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.ports);
}
@@ -1373,7 +1366,7 @@ static ssize_t bonding_show_ad_actor_key(struct device *d,
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
- (bond_3ad_get_active_agg_info(bond, &ad_info))
+ bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.actor_key);
}
@@ -1395,7 +1388,7 @@ static ssize_t bonding_show_ad_partner_key(struct device *d,
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
count = sprintf(buf, "%d\n",
- (bond_3ad_get_active_agg_info(bond, &ad_info))
+ bond_3ad_get_active_agg_info(bond, &ad_info)
? 0 : ad_info.partner_key);
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 2baec24..c990b42 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -225,13 +225,12 @@ struct bonding {
rwlock_t curr_slave_lock;
u8 send_peer_notif;
s8 setup_by_slave;
- s8 igmp_retrans;
+ u8 igmp_retrans;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry;
char proc_file_name[IFNAMSIZ];
#endif /* CONFIG_PROC_FS */
struct list_head bond_list;
- struct netdev_hw_addr_list mc_list;
int (*xmit_hash_policy)(struct sk_buff *, int);
u16 rr_tx_counter;
struct ad_bond_info ad_info;
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 7ffc756..5470980 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -43,7 +43,7 @@ config CAIF_HSI
config CAIF_VIRTIO
tristate "CAIF virtio transport driver"
- depends on CAIF
+ depends on CAIF && HAS_DMA
select VHOST_RING
select VIRTIO
select GENERIC_ALLOCATOR
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index e456b70..3c06947 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -102,12 +102,9 @@ config CAN_JANZ_ICAN3
This driver can also be built as a module. If so, the module will be
called janz-ican3.ko.
-config HAVE_CAN_FLEXCAN
- bool
-
config CAN_FLEXCAN
tristate "Support for Freescale FLEXCAN based chips"
- depends on HAVE_CAN_FLEXCAN
+ depends on ARM || PPC
---help---
Say Y here if you want to support for Freescale FlexCAN.
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index db52f441..ce8421a 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -1220,7 +1220,7 @@ static ssize_t at91_sysfs_set_mb0_id(struct device *dev,
goto out;
}
- err = strict_strtoul(buf, 0, &can_id);
+ err = kstrtoul(buf, 0, &can_id);
if (err) {
ret = err;
goto out;
@@ -1393,8 +1393,6 @@ static int at91_can_remove(struct platform_device *pdev)
unregister_netdev(dev);
- platform_set_drvdata(pdev, NULL);
-
iounmap(priv->reg_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index d4a15e8..a2700d2 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -580,7 +580,7 @@ static int bfin_can_probe(struct platform_device *pdev)
priv->pin_list = pdata;
priv->can.clock.freq = get_sclk();
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
dev->flags |= IFF_ECHO; /* we support local echo */
@@ -613,7 +613,7 @@ exit:
static int bfin_can_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct bfin_can_priv *priv = netdev_priv(dev);
struct resource *res;
@@ -621,8 +621,6 @@ static int bfin_can_remove(struct platform_device *pdev)
unregister_candev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
@@ -635,7 +633,7 @@ static int bfin_can_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
int timeout = BFIN_CAN_TIMEOUT;
@@ -658,7 +656,7 @@ static int bfin_can_suspend(struct platform_device *pdev, pm_message_t mesg)
static int bfin_can_resume(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct bfin_can_priv *priv = netdev_priv(dev);
struct bfin_can_regs __iomem *reg = priv->membase;
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index d63b919..b918c73 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -201,8 +201,8 @@ static int c_can_plat_probe(struct platform_device *pdev)
priv->instance = pdev->id;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- priv->raminit_ctrlreg = devm_request_and_ioremap(&pdev->dev, res);
- if (!priv->raminit_ctrlreg || priv->instance < 0)
+ priv->raminit_ctrlreg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->raminit_ctrlreg) || priv->instance < 0)
dev_info(&pdev->dev, "control memory is not used for raminit\n");
else
priv->raminit = c_can_hw_raminit;
@@ -234,7 +234,6 @@ static int c_can_plat_probe(struct platform_device *pdev)
return 0;
exit_free_device:
- platform_set_drvdata(pdev, NULL);
free_c_can_dev(dev);
exit_iounmap:
iounmap(addr);
@@ -255,7 +254,6 @@ static int c_can_plat_remove(struct platform_device *pdev)
struct resource *mem;
unregister_c_can_dev(dev);
- platform_set_drvdata(pdev, NULL);
free_c_can_dev(dev);
iounmap(priv->base);
diff --git a/drivers/net/can/cc770/cc770_isa.c b/drivers/net/can/cc770/cc770_isa.c
index 8eaaac8..87a47c0 100644
--- a/drivers/net/can/cc770/cc770_isa.c
+++ b/drivers/net/can/cc770/cc770_isa.c
@@ -265,7 +265,7 @@ static int cc770_isa_probe(struct platform_device *pdev)
else
priv->clkout = COR_DEFAULT;
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_cc770dev(dev);
@@ -293,12 +293,11 @@ static int cc770_isa_probe(struct platform_device *pdev)
static int cc770_isa_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct cc770_priv *priv = netdev_priv(dev);
int idx = pdev->id;
unregister_cc770dev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
if (mem[idx]) {
iounmap(priv->reg_base);
diff --git a/drivers/net/can/cc770/cc770_platform.c b/drivers/net/can/cc770/cc770_platform.c
index d0f6bfc..034bdd8 100644
--- a/drivers/net/can/cc770/cc770_platform.c
+++ b/drivers/net/can/cc770/cc770_platform.c
@@ -216,7 +216,7 @@ static int cc770_platform_probe(struct platform_device *pdev)
priv->reg_base, dev->irq, priv->can.clock.freq,
priv->cpu_interface, priv->bus_config, priv->clkout);
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_cc770dev(dev);
@@ -240,7 +240,7 @@ exit_release_mem:
static int cc770_platform_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct cc770_priv *priv = netdev_priv(dev);
struct resource *mem;
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 769d29e..f873b9f 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -37,7 +37,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
-#include <linux/pinctrl/consumer.h>
#define DRV_NAME "flexcan"
@@ -1004,16 +1003,11 @@ static int flexcan_probe(struct platform_device *pdev)
struct flexcan_priv *priv;
struct resource *mem;
struct clk *clk_ipg = NULL, *clk_per = NULL;
- struct pinctrl *pinctrl;
void __iomem *base;
resource_size_t mem_size;
int err, irq;
u32 clock_freq = 0;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl))
- return PTR_ERR(pinctrl);
-
if (pdev->dev.of_node)
of_property_read_u32(pdev->dev.of_node,
"clock-frequency", &clock_freq);
@@ -1127,7 +1121,6 @@ static int flexcan_remove(struct platform_device *pdev)
struct resource *mem;
unregister_flexcandev(dev);
- platform_set_drvdata(pdev, NULL);
iounmap(priv->base);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1138,10 +1131,10 @@ static int flexcan_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int flexcan_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int flexcan_suspend(struct device *device)
{
- struct net_device *dev = platform_get_drvdata(pdev);
+ struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
flexcan_chip_disable(priv);
@@ -1155,9 +1148,9 @@ static int flexcan_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int flexcan_resume(struct platform_device *pdev)
+static int flexcan_resume(struct device *device)
{
- struct net_device *dev = platform_get_drvdata(pdev);
+ struct net_device *dev = dev_get_drvdata(device);
struct flexcan_priv *priv = netdev_priv(dev);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
@@ -1169,21 +1162,19 @@ static int flexcan_resume(struct platform_device *pdev)
return 0;
}
-#else
-#define flexcan_suspend NULL
-#define flexcan_resume NULL
-#endif
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
static struct platform_driver flexcan_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &flexcan_pm_ops,
.of_match_table = flexcan_of_match,
},
.probe = flexcan_probe,
.remove = flexcan_remove,
- .suspend = flexcan_suspend,
- .resume = flexcan_resume,
.id_table = flexcan_id_table,
};
diff --git a/drivers/net/can/grcan.c b/drivers/net/can/grcan.c
index 17fbc7a..6aa737a 100644
--- a/drivers/net/can/grcan.c
+++ b/drivers/net/can/grcan.c
@@ -1646,7 +1646,7 @@ static int grcan_setup_netdev(struct platform_device *ofdev,
if (err)
goto exit_free_candev;
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
/* Reset device to allow bit-timing to be set. No need to call
* grcan_reset at this stage. That is done in grcan_open.
@@ -1683,10 +1683,9 @@ static int grcan_probe(struct platform_device *ofdev)
}
res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
- base = devm_request_and_ioremap(&ofdev->dev, res);
- if (!base) {
- dev_err(&ofdev->dev, "couldn't map IO resource\n");
- err = -EADDRNOTAVAIL;
+ base = devm_ioremap_resource(&ofdev->dev, res);
+ if (IS_ERR(base)) {
+ err = PTR_ERR(base);
goto exit_error;
}
@@ -1716,13 +1715,12 @@ exit_error:
static int grcan_remove(struct platform_device *ofdev)
{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ struct net_device *dev = platform_get_drvdata(ofdev);
struct grcan_priv *priv = netdev_priv(dev);
unregister_candev(dev); /* Will in turn call grcan_close */
irq_dispose_mapping(dev->irq);
- dev_set_drvdata(&ofdev->dev, NULL);
netif_napi_del(&priv->napi);
free_candev(dev);
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index c4bc1d2..36bd6fa1 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -1734,7 +1734,7 @@ static ssize_t ican3_sysfs_set_term(struct device *dev,
unsigned long enable;
int ret;
- if (strict_strtoul(buf, 0, &enable))
+ if (kstrtoul(buf, 0, &enable))
return -EINVAL;
ret = ican3_set_termination(mod, enable);
diff --git a/drivers/net/can/led.c b/drivers/net/can/led.c
index f27fca6..a3d99a8 100644
--- a/drivers/net/can/led.c
+++ b/drivers/net/can/led.c
@@ -88,9 +88,9 @@ EXPORT_SYMBOL_GPL(devm_can_led_init);
/* NETDEV rename notifier to rename the associated led triggers too */
static int can_led_notifier(struct notifier_block *nb, unsigned long msg,
- void *data)
+ void *ptr)
{
- struct net_device *netdev = data;
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
struct can_priv *priv = safe_candev_priv(netdev);
char name[CAN_LED_NAME_SZ];
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 668850e..5b0ee8e 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -302,7 +302,7 @@ static int mpc5xxx_can_probe(struct platform_device *ofdev)
goto exit_free_mscan;
}
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
priv->reg_base, dev->irq, priv->can.clock.freq);
@@ -321,11 +321,9 @@ exit_unmap_mem:
static int mpc5xxx_can_remove(struct platform_device *ofdev)
{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ struct net_device *dev = platform_get_drvdata(ofdev);
struct mscan_priv *priv = netdev_priv(dev);
- dev_set_drvdata(&ofdev->dev, NULL);
-
unregister_mscandev(dev);
iounmap(priv->reg_base);
irq_dispose_mapping(dev->irq);
@@ -338,7 +336,7 @@ static int mpc5xxx_can_remove(struct platform_device *ofdev)
static struct mscan_regs saved_regs;
static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state)
{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ struct net_device *dev = platform_get_drvdata(ofdev);
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
@@ -349,7 +347,7 @@ static int mpc5xxx_can_suspend(struct platform_device *ofdev, pm_message_t state
static int mpc5xxx_can_resume(struct platform_device *ofdev)
{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ struct net_device *dev = platform_get_drvdata(ofdev);
struct mscan_priv *priv = netdev_priv(dev);
struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
diff --git a/drivers/net/can/sja1000/sja1000_isa.c b/drivers/net/can/sja1000/sja1000_isa.c
index 5c8da46..06a2823 100644
--- a/drivers/net/can/sja1000/sja1000_isa.c
+++ b/drivers/net/can/sja1000/sja1000_isa.c
@@ -197,7 +197,7 @@ static int sja1000_isa_probe(struct platform_device *pdev)
else
priv->cdr = CDR_DEFAULT;
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_sja1000dev(dev);
@@ -225,12 +225,11 @@ static int sja1000_isa_probe(struct platform_device *pdev)
static int sja1000_isa_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct sja1000_priv *priv = netdev_priv(dev);
int idx = pdev->id;
unregister_sja1000dev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
if (mem[idx]) {
iounmap(priv->reg_base);
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
index 8e0c4a0..31ad339 100644
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ b/drivers/net/can/sja1000/sja1000_of_platform.c
@@ -72,13 +72,11 @@ static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
static int sja1000_ofp_remove(struct platform_device *ofdev)
{
- struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ struct net_device *dev = platform_get_drvdata(ofdev);
struct sja1000_priv *priv = netdev_priv(dev);
struct device_node *np = ofdev->dev.of_node;
struct resource res;
- dev_set_drvdata(&ofdev->dev, NULL);
-
unregister_sja1000dev(dev);
free_sja1000dev(dev);
iounmap(priv->reg_base);
@@ -181,7 +179,7 @@ static int sja1000_ofp_probe(struct platform_device *ofdev)
priv->reg_base, dev->irq, priv->can.clock.freq,
priv->ocr, priv->cdr);
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
SET_NETDEV_DEV(dev, &ofdev->dev);
err = register_sja1000dev(dev);
diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c
index 21619bb..8e259c54 100644
--- a/drivers/net/can/sja1000/sja1000_platform.c
+++ b/drivers/net/can/sja1000/sja1000_platform.c
@@ -135,7 +135,7 @@ static int sp_probe(struct platform_device *pdev)
break;
}
- dev_set_drvdata(&pdev->dev, dev);
+ platform_set_drvdata(pdev, dev);
SET_NETDEV_DEV(dev, &pdev->dev);
err = register_sja1000dev(dev);
@@ -161,12 +161,11 @@ static int sp_probe(struct platform_device *pdev)
static int sp_remove(struct platform_device *pdev)
{
- struct net_device *dev = dev_get_drvdata(&pdev->dev);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct sja1000_priv *priv = netdev_priv(dev);
struct resource *res;
unregister_sja1000dev(dev);
- dev_set_drvdata(&pdev->dev, NULL);
if (priv->reg_base)
iounmap(priv->reg_base);
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 06b7e09..874188b 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -161,7 +161,7 @@ static void slc_bump(struct slcan *sl)
sl->rbuff[dlc_pos] = 0; /* terminate can_id string */
- if (strict_strtoul(sl->rbuff+1, 16, &ultmp))
+ if (kstrtoul(sl->rbuff+1, 16, &ultmp))
return;
cf.can_id = ultmp;
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
index 3a2b456..65eef1e 100644
--- a/drivers/net/can/softing/softing_main.c
+++ b/drivers/net/can/softing/softing_main.c
@@ -594,7 +594,7 @@ static ssize_t store_output(struct device *dev, struct device_attribute *attr,
unsigned long val;
int ret;
- ret = strict_strtoul(buf, 0, &val);
+ ret = kstrtoul(buf, 0, &val);
if (ret < 0)
return ret;
val &= 0xFF;
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index f21fc37..3a349a2 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -1001,7 +1001,6 @@ static int ti_hecc_remove(struct platform_device *pdev)
iounmap(priv->base);
release_mem_region(res->start, resource_size(res));
free_candev(ndev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index 9b74d1e..6aa7b32 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -612,9 +612,15 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
{
struct esd_usb2 *dev = priv->usb2;
struct net_device *netdev = priv->netdev;
- struct esd_usb2_msg msg;
+ struct esd_usb2_msg *msg;
int err, i;
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
/*
* Enable all IDs
* The IDADD message takes up to 64 32 bit bitmasks (2048 bits).
@@ -628,33 +634,32 @@ static int esd_usb2_start(struct esd_usb2_net_priv *priv)
* the number of the starting bitmask (0..64) to the filter.option
* field followed by only some bitmasks.
*/
- msg.msg.hdr.cmd = CMD_IDADD;
- msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
- msg.msg.filter.net = priv->index;
- msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+ msg->msg.hdr.cmd = CMD_IDADD;
+ msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+ msg->msg.filter.net = priv->index;
+ msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
for (i = 0; i < ESD_MAX_ID_SEGMENT; i++)
- msg.msg.filter.mask[i] = cpu_to_le32(0xffffffff);
+ msg->msg.filter.mask[i] = cpu_to_le32(0xffffffff);
/* enable 29bit extended IDs */
- msg.msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
+ msg->msg.filter.mask[ESD_MAX_ID_SEGMENT] = cpu_to_le32(0x00000001);
- err = esd_usb2_send_msg(dev, &msg);
+ err = esd_usb2_send_msg(dev, msg);
if (err)
- goto failed;
+ goto out;
err = esd_usb2_setup_rx_urbs(dev);
if (err)
- goto failed;
+ goto out;
priv->can.state = CAN_STATE_ERROR_ACTIVE;
- return 0;
-
-failed:
+out:
if (err == -ENODEV)
netif_device_detach(netdev);
+ if (err)
+ netdev_err(netdev, "couldn't start device: %d\n", err);
- netdev_err(netdev, "couldn't start device: %d\n", err);
-
+ kfree(msg);
return err;
}
@@ -833,26 +838,30 @@ nourbmem:
static int esd_usb2_close(struct net_device *netdev)
{
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
- struct esd_usb2_msg msg;
+ struct esd_usb2_msg *msg;
int i;
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
/* Disable all IDs (see esd_usb2_start()) */
- msg.msg.hdr.cmd = CMD_IDADD;
- msg.msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
- msg.msg.filter.net = priv->index;
- msg.msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
+ msg->msg.hdr.cmd = CMD_IDADD;
+ msg->msg.hdr.len = 2 + ESD_MAX_ID_SEGMENT;
+ msg->msg.filter.net = priv->index;
+ msg->msg.filter.option = ESD_ID_ENABLE; /* start with segment 0 */
for (i = 0; i <= ESD_MAX_ID_SEGMENT; i++)
- msg.msg.filter.mask[i] = 0;
- if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+ msg->msg.filter.mask[i] = 0;
+ if (esd_usb2_send_msg(priv->usb2, msg) < 0)
netdev_err(netdev, "sending idadd message failed\n");
/* set CAN controller to reset mode */
- msg.msg.hdr.len = 2;
- msg.msg.hdr.cmd = CMD_SETBAUD;
- msg.msg.setbaud.net = priv->index;
- msg.msg.setbaud.rsvd = 0;
- msg.msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
- if (esd_usb2_send_msg(priv->usb2, &msg) < 0)
+ msg->msg.hdr.len = 2;
+ msg->msg.hdr.cmd = CMD_SETBAUD;
+ msg->msg.setbaud.net = priv->index;
+ msg->msg.setbaud.rsvd = 0;
+ msg->msg.setbaud.baud = cpu_to_le32(ESD_USB2_NO_BAUDRATE);
+ if (esd_usb2_send_msg(priv->usb2, msg) < 0)
netdev_err(netdev, "sending setbaud message failed\n");
priv->can.state = CAN_STATE_STOPPED;
@@ -861,6 +870,8 @@ static int esd_usb2_close(struct net_device *netdev)
close_candev(netdev);
+ kfree(msg);
+
return 0;
}
@@ -886,7 +897,8 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
{
struct esd_usb2_net_priv *priv = netdev_priv(netdev);
struct can_bittiming *bt = &priv->can.bittiming;
- struct esd_usb2_msg msg;
+ struct esd_usb2_msg *msg;
+ int err;
u32 canbtr;
int sjw_shift;
@@ -912,15 +924,22 @@ static int esd_usb2_set_bittiming(struct net_device *netdev)
if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
canbtr |= ESD_USB2_3_SAMPLES;
- msg.msg.hdr.len = 2;
- msg.msg.hdr.cmd = CMD_SETBAUD;
- msg.msg.setbaud.net = priv->index;
- msg.msg.setbaud.rsvd = 0;
- msg.msg.setbaud.baud = cpu_to_le32(canbtr);
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->msg.hdr.len = 2;
+ msg->msg.hdr.cmd = CMD_SETBAUD;
+ msg->msg.setbaud.net = priv->index;
+ msg->msg.setbaud.rsvd = 0;
+ msg->msg.setbaud.baud = cpu_to_le32(canbtr);
netdev_info(netdev, "setting BTR=%#x\n", canbtr);
- return esd_usb2_send_msg(priv->usb2, &msg);
+ err = esd_usb2_send_msg(priv->usb2, msg);
+
+ kfree(msg);
+ return err;
}
static int esd_usb2_get_berr_counter(const struct net_device *netdev,
@@ -1022,7 +1041,7 @@ static int esd_usb2_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct esd_usb2 *dev;
- struct esd_usb2_msg msg;
+ struct esd_usb2_msg *msg;
int i, err;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1037,27 +1056,33 @@ static int esd_usb2_probe(struct usb_interface *intf,
usb_set_intfdata(intf, dev);
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg) {
+ err = -ENOMEM;
+ goto free_msg;
+ }
+
/* query number of CAN interfaces (nets) */
- msg.msg.hdr.cmd = CMD_VERSION;
- msg.msg.hdr.len = 2;
- msg.msg.version.rsvd = 0;
- msg.msg.version.flags = 0;
- msg.msg.version.drv_version = 0;
+ msg->msg.hdr.cmd = CMD_VERSION;
+ msg->msg.hdr.len = 2;
+ msg->msg.version.rsvd = 0;
+ msg->msg.version.flags = 0;
+ msg->msg.version.drv_version = 0;
- err = esd_usb2_send_msg(dev, &msg);
+ err = esd_usb2_send_msg(dev, msg);
if (err < 0) {
dev_err(&intf->dev, "sending version message failed\n");
- goto free_dev;
+ goto free_msg;
}
- err = esd_usb2_wait_msg(dev, &msg);
+ err = esd_usb2_wait_msg(dev, msg);
if (err < 0) {
dev_err(&intf->dev, "no version message answer\n");
- goto free_dev;
+ goto free_msg;
}
- dev->net_count = (int)msg.msg.version_reply.nets;
- dev->version = le32_to_cpu(msg.msg.version_reply.version);
+ dev->net_count = (int)msg->msg.version_reply.nets;
+ dev->version = le32_to_cpu(msg->msg.version_reply.version);
if (device_create_file(&intf->dev, &dev_attr_firmware))
dev_err(&intf->dev,
@@ -1075,10 +1100,10 @@ static int esd_usb2_probe(struct usb_interface *intf,
for (i = 0; i < dev->net_count; i++)
esd_usb2_probe_one_net(intf, i);
- return 0;
-
-free_dev:
- kfree(dev);
+free_msg:
+ kfree(msg);
+ if (err)
+ kfree(dev);
done:
return err;
}
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 45cb9f3..3b95465 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -136,6 +136,9 @@
#define KVASER_CTRL_MODE_SELFRECEPTION 3
#define KVASER_CTRL_MODE_OFF 4
+/* log message */
+#define KVASER_EXTENDED_FRAME BIT(31)
+
struct kvaser_msg_simple {
u8 tid;
u8 channel;
@@ -817,8 +820,13 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
priv = dev->nets[channel];
stats = &priv->netdev->stats;
- if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME | MSG_FLAG_NERR |
- MSG_FLAG_OVERRUN)) {
+ if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) &&
+ (msg->id == CMD_LOG_MESSAGE)) {
+ kvaser_usb_rx_error(dev, msg);
+ return;
+ } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+ MSG_FLAG_NERR |
+ MSG_FLAG_OVERRUN)) {
kvaser_usb_rx_can_err(priv, msg);
return;
} else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
@@ -834,22 +842,40 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
return;
}
- cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
- (msg->u.rx_can.msg[1] & 0x3f);
- cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+ if (msg->id == CMD_LOG_MESSAGE) {
+ cf->can_id = le32_to_cpu(msg->u.log_message.id);
+ if (cf->can_id & KVASER_EXTENDED_FRAME)
+ cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
+ else
+ cf->can_id &= CAN_SFF_MASK;
- if (msg->id == CMD_RX_EXT_MESSAGE) {
- cf->can_id <<= 18;
- cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
- ((msg->u.rx_can.msg[3] & 0xff) << 6) |
- (msg->u.rx_can.msg[4] & 0x3f);
- cf->can_id |= CAN_EFF_FLAG;
- }
+ cf->can_dlc = get_can_dlc(msg->u.log_message.dlc);
- if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
- cf->can_id |= CAN_RTR_FLAG;
- else
- memcpy(cf->data, &msg->u.rx_can.msg[6], cf->can_dlc);
+ if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+ memcpy(cf->data, &msg->u.log_message.data,
+ cf->can_dlc);
+ } else {
+ cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
+ (msg->u.rx_can.msg[1] & 0x3f);
+
+ if (msg->id == CMD_RX_EXT_MESSAGE) {
+ cf->can_id <<= 18;
+ cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
+ ((msg->u.rx_can.msg[3] & 0xff) << 6) |
+ (msg->u.rx_can.msg[4] & 0x3f);
+ cf->can_id |= CAN_EFF_FLAG;
+ }
+
+ cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+
+ if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
+ cf->can_id |= CAN_RTR_FLAG;
+ else
+ memcpy(cf->data, &msg->u.rx_can.msg[6],
+ cf->can_dlc);
+ }
netif_rx(skb);
@@ -911,6 +937,7 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
case CMD_RX_STD_MESSAGE:
case CMD_RX_EXT_MESSAGE:
+ case CMD_LOG_MESSAGE:
kvaser_usb_rx_can_msg(dev, msg);
break;
@@ -919,11 +946,6 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
kvaser_usb_rx_error(dev, msg);
break;
- case CMD_LOG_MESSAGE:
- if (msg->u.log_message.flags & MSG_FLAG_ERROR_FRAME)
- kvaser_usb_rx_error(dev, msg);
- break;
-
case CMD_TX_ACKNOWLEDGE:
kvaser_usb_tx_acknowledge(dev, msg);
break;
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index 30d79bf..8ee9d15 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -504,15 +504,24 @@ static int pcan_usb_pro_restart_async(struct peak_usb_device *dev,
return usb_submit_urb(urb, GFP_ATOMIC);
}
-static void pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded)
+static int pcan_usb_pro_drv_loaded(struct peak_usb_device *dev, int loaded)
{
- u8 buffer[16];
+ u8 *buffer;
+ int err;
+
+ buffer = kmalloc(PCAN_USBPRO_FCT_DRVLD_REQ_LEN, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
buffer[0] = 0;
buffer[1] = !!loaded;
- pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT,
- PCAN_USBPRO_FCT_DRVLD, buffer, sizeof(buffer));
+ err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_FCT,
+ PCAN_USBPRO_FCT_DRVLD, buffer,
+ PCAN_USBPRO_FCT_DRVLD_REQ_LEN);
+ kfree(buffer);
+
+ return err;
}
static inline
@@ -851,21 +860,24 @@ static int pcan_usb_pro_stop(struct peak_usb_device *dev)
*/
static int pcan_usb_pro_init(struct peak_usb_device *dev)
{
- struct pcan_usb_pro_interface *usb_if;
struct pcan_usb_pro_device *pdev =
container_of(dev, struct pcan_usb_pro_device, dev);
+ struct pcan_usb_pro_interface *usb_if = NULL;
+ struct pcan_usb_pro_fwinfo *fi = NULL;
+ struct pcan_usb_pro_blinfo *bi = NULL;
+ int err;
/* do this for 1st channel only */
if (!dev->prev_siblings) {
- struct pcan_usb_pro_fwinfo fi;
- struct pcan_usb_pro_blinfo bi;
- int err;
-
/* allocate netdevices common structure attached to first one */
usb_if = kzalloc(sizeof(struct pcan_usb_pro_interface),
GFP_KERNEL);
- if (!usb_if)
- return -ENOMEM;
+ fi = kmalloc(sizeof(struct pcan_usb_pro_fwinfo), GFP_KERNEL);
+ bi = kmalloc(sizeof(struct pcan_usb_pro_blinfo), GFP_KERNEL);
+ if (!usb_if || !fi || !bi) {
+ err = -ENOMEM;
+ goto err_out;
+ }
/* number of ts msgs to ignore before taking one into account */
usb_if->cm_ignore_count = 5;
@@ -877,34 +889,34 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
*/
err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
PCAN_USBPRO_INFO_FW,
- &fi, sizeof(fi));
+ fi, sizeof(*fi));
if (err) {
- kfree(usb_if);
dev_err(dev->netdev->dev.parent,
"unable to read %s firmware info (err %d)\n",
pcan_usb_pro.name, err);
- return err;
+ goto err_out;
}
err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
PCAN_USBPRO_INFO_BL,
- &bi, sizeof(bi));
+ bi, sizeof(*bi));
if (err) {
- kfree(usb_if);
dev_err(dev->netdev->dev.parent,
"unable to read %s bootloader info (err %d)\n",
pcan_usb_pro.name, err);
- return err;
+ goto err_out;
}
+ /* tell the device the can driver is running */
+ err = pcan_usb_pro_drv_loaded(dev, 1);
+ if (err)
+ goto err_out;
+
dev_info(dev->netdev->dev.parent,
"PEAK-System %s hwrev %u serial %08X.%08X (%u channels)\n",
pcan_usb_pro.name,
- bi.hw_rev, bi.serial_num_hi, bi.serial_num_lo,
+ bi->hw_rev, bi->serial_num_hi, bi->serial_num_lo,
pcan_usb_pro.ctrl_count);
-
- /* tell the device the can driver is running */
- pcan_usb_pro_drv_loaded(dev, 1);
} else {
usb_if = pcan_usb_pro_dev_if(dev->prev_siblings);
}
@@ -916,6 +928,13 @@ static int pcan_usb_pro_init(struct peak_usb_device *dev)
pcan_usb_pro_set_led(dev, 0, 1);
return 0;
+
+ err_out:
+ kfree(bi);
+ kfree(fi);
+ kfree(usb_if);
+
+ return err;
}
static void pcan_usb_pro_exit(struct peak_usb_device *dev)
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
index a869918..32275af 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
@@ -29,6 +29,7 @@
/* Vendor Request value for XXX_FCT */
#define PCAN_USBPRO_FCT_DRVLD 5 /* tell device driver is loaded */
+#define PCAN_USBPRO_FCT_DRVLD_REQ_LEN 16
/* PCAN_USBPRO_INFO_BL vendor request record type */
struct __packed pcan_usb_pro_blinfo {
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
index 6e15ef0..cbd388e 100644
--- a/drivers/net/can/usb/usb_8dev.c
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -977,7 +977,7 @@ static int usb_8dev_probe(struct usb_interface *intf,
err = usb_8dev_cmd_version(priv, &version);
if (err) {
netdev_err(netdev, "can't get firmware version\n");
- goto cleanup_cmd_msg_buffer;
+ goto cleanup_unregister_candev;
} else {
netdev_info(netdev,
"firmware: %d.%d, hardware: %d.%d\n",
@@ -989,6 +989,9 @@ static int usb_8dev_probe(struct usb_interface *intf,
return 0;
+cleanup_unregister_candev:
+ unregister_netdev(priv->netdev);
+
cleanup_cmd_msg_buffer:
kfree(priv->cmd_msg_buffer);
diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c
index adb4bf5..ede8daa 100644
--- a/drivers/net/ethernet/3com/3c509.c
+++ b/drivers/net/ethernet/3com/3c509.c
@@ -723,25 +723,6 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pr_debug("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
dev->name, skb->len, inw(ioaddr + EL3_STATUS));
}
-#if 0
-#ifndef final_version
- { /* Error-checking code, delete someday. */
- ushort status = inw(ioaddr + EL3_STATUS);
- if (status & 0x0001 && /* IRQ line active, missed one. */
- inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */
- pr_debug("%s: Missed interrupt, status then %04x now %04x"
- " Tx %2.2x Rx %4.4x.\n", dev->name, status,
- inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),
- inw(ioaddr + RX_STATUS));
- /* Fake interrupt trigger by masking, acknowledge interrupts. */
- outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
- outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
- ioaddr + EL3_CMD);
- outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
- }
- }
-#endif
-#endif
/*
* We lock the driver against other processors. Note
* we don't need to lock versus the IRQ as we suspended
diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c
index de570a8..ad5272b 100644
--- a/drivers/net/ethernet/3com/3c59x.c
+++ b/drivers/net/ethernet/3com/3c59x.c
@@ -632,7 +632,6 @@ struct vortex_private {
pm_state_valid:1, /* pci_dev->saved_config_space has sane contents */
open:1,
medialock:1,
- must_free_region:1, /* Flag: if zero, Cardbus owns the I/O region */
large_frames:1, /* accept large frames */
handling_irq:1; /* private in_irq indicator */
/* {get|set}_wol operations are already serialized by rtnl.
@@ -1012,6 +1011,10 @@ static int vortex_init_one(struct pci_dev *pdev,
if (rc < 0)
goto out;
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc < 0)
+ goto out_disable;
+
unit = vortex_cards_found;
if (global_use_mmio < 0 && (unit >= MAX_UNITS || use_mmio[unit] < 0)) {
@@ -1027,21 +1030,24 @@ static int vortex_init_one(struct pci_dev *pdev,
if (!ioaddr) /* If mapping fails, fall-back to BAR 0... */
ioaddr = pci_iomap(pdev, 0, 0);
if (!ioaddr) {
- pci_disable_device(pdev);
rc = -ENOMEM;
- goto out;
+ goto out_release;
}
rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq,
ent->driver_data, unit);
- if (rc < 0) {
- pci_iounmap(pdev, ioaddr);
- pci_disable_device(pdev);
- goto out;
- }
+ if (rc < 0)
+ goto out_iounmap;
vortex_cards_found++;
-
+ goto out;
+
+out_iounmap:
+ pci_iounmap(pdev, ioaddr);
+out_release:
+ pci_release_regions(pdev);
+out_disable:
+ pci_disable_device(pdev);
out:
return rc;
}
@@ -1178,11 +1184,6 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
/* PCI-only startup logic */
if (pdev) {
- /* EISA resources already marked, so only PCI needs to do this here */
- /* Ignore return value, because Cardbus drivers already allocate for us */
- if (request_region(dev->base_addr, vci->io_size, print_name) != NULL)
- vp->must_free_region = 1;
-
/* enable bus-mastering if necessary */
if (vci->flags & PCI_USES_MASTER)
pci_set_master(pdev);
@@ -1220,7 +1221,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
&vp->rx_ring_dma);
retval = -ENOMEM;
if (!vp->rx_ring)
- goto free_region;
+ goto free_device;
vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
@@ -1471,7 +1472,7 @@ static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
if (pdev) {
vp->pm_state_valid = 1;
- pci_save_state(VORTEX_PCI(vp));
+ pci_save_state(pdev);
acpi_set_WOL(dev);
}
retval = register_netdev(dev);
@@ -1484,9 +1485,7 @@ free_ring:
+ sizeof(struct boom_tx_desc) * TX_RING_SIZE,
vp->rx_ring,
vp->rx_ring_dma);
-free_region:
- if (vp->must_free_region)
- release_region(dev->base_addr, vci->io_size);
+free_device:
free_netdev(dev);
pr_err(PFX "vortex_probe1 fails. Returns %d\n", retval);
out:
@@ -3233,29 +3232,29 @@ static void vortex_remove_one(struct pci_dev *pdev)
vp = netdev_priv(dev);
if (vp->cb_fn_base)
- pci_iounmap(VORTEX_PCI(vp), vp->cb_fn_base);
+ pci_iounmap(pdev, vp->cb_fn_base);
unregister_netdev(dev);
- if (VORTEX_PCI(vp)) {
- pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */
- if (vp->pm_state_valid)
- pci_restore_state(VORTEX_PCI(vp));
- pci_disable_device(VORTEX_PCI(vp));
- }
+ pci_set_power_state(pdev, PCI_D0); /* Go active */
+ if (vp->pm_state_valid)
+ pci_restore_state(pdev);
+ pci_disable_device(pdev);
+
/* Should really use issue_and_wait() here */
iowrite16(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14),
vp->ioaddr + EL3_CMD);
- pci_iounmap(VORTEX_PCI(vp), vp->ioaddr);
+ pci_iounmap(pdev, vp->ioaddr);
pci_free_consistent(pdev,
sizeof(struct boom_rx_desc) * RX_RING_SIZE
+ sizeof(struct boom_tx_desc) * TX_RING_SIZE,
vp->rx_ring,
vp->rx_ring_dma);
- if (vp->must_free_region)
- release_region(dev->base_addr, vp->io_size);
+
+ pci_release_regions(pdev);
+
free_netdev(dev);
}
diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig
index 1c71c76..f00c763 100644
--- a/drivers/net/ethernet/3com/Kconfig
+++ b/drivers/net/ethernet/3com/Kconfig
@@ -67,7 +67,6 @@ config PCMCIA_3C589
config VORTEX
tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
depends on (PCI || EISA) && HAS_IOPORT
- select NET_CORE
select MII
---help---
This option enables driver support for a large number of 10Mbps and
diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c
index 47618e5..b2e8405 100644
--- a/drivers/net/ethernet/8390/ne.c
+++ b/drivers/net/ethernet/8390/ne.c
@@ -849,7 +849,6 @@ static int ne_drv_remove(struct platform_device *pdev)
free_irq(dev->irq, dev);
release_region(dev->base_addr, NE_IO_EXTENT);
free_netdev(dev);
- platform_set_drvdata(pdev, NULL);
}
return 0;
}
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index ed956e0..a989669 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -20,6 +20,7 @@ config SUNGEM_PHY
source "drivers/net/ethernet/3com/Kconfig"
source "drivers/net/ethernet/adaptec/Kconfig"
source "drivers/net/ethernet/aeroflex/Kconfig"
+source "drivers/net/ethernet/allwinner/Kconfig"
source "drivers/net/ethernet/alteon/Kconfig"
source "drivers/net/ethernet/amd/Kconfig"
source "drivers/net/ethernet/apple/Kconfig"
@@ -63,7 +64,6 @@ config JME
tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This driver supports the PCI-Express gigabit ethernet adapters
@@ -95,7 +95,6 @@ config FEALNX
tristate "Myson MTD-8xx PCI Ethernet support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
Say Y here to support the Myson MTD-800 family of PCI-based Ethernet
@@ -106,7 +105,6 @@ source "drivers/net/ethernet/8390/Kconfig"
config NET_NETX
tristate "NetX Ethernet support"
- select NET_CORE
select MII
depends on ARCH_NETX
---help---
@@ -124,7 +122,6 @@ source "drivers/net/ethernet/oki-semi/Kconfig"
config ETHOC
tristate "OpenCores 10/100 Mbps Ethernet MAC support"
depends on HAS_IOMEM && HAS_DMA
- select NET_CORE
select MII
select PHYLIB
select CRC32
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 8268d85..009da27 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_NET_VENDOR_3COM) += 3com/
obj-$(CONFIG_NET_VENDOR_8390) += 8390/
obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/
obj-$(CONFIG_GRETH) += aeroflex/
+obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/
obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
obj-$(CONFIG_NET_VENDOR_AMD) += amd/
obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
diff --git a/drivers/net/ethernet/adaptec/Kconfig b/drivers/net/ethernet/adaptec/Kconfig
index 0bff571..5c804bb 100644
--- a/drivers/net/ethernet/adaptec/Kconfig
+++ b/drivers/net/ethernet/adaptec/Kconfig
@@ -22,7 +22,6 @@ config ADAPTEC_STARFIRE
tristate "Adaptec Starfire/DuraLAN support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig
index a948160..f952fff 100644
--- a/drivers/net/ethernet/adi/Kconfig
+++ b/drivers/net/ethernet/adi/Kconfig
@@ -23,7 +23,6 @@ config BFIN_MAC
tristate "Blackfin on-chip MAC support"
depends on (BF516 || BF518 || BF526 || BF527 || BF536 || BF537)
select CRC32
- select NET_CORE
select MII
select PHYLIB
select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
diff --git a/drivers/net/ethernet/adi/bfin_mac.c b/drivers/net/ethernet/adi/bfin_mac.c
index dada66b..e904b38 100644
--- a/drivers/net/ethernet/adi/bfin_mac.c
+++ b/drivers/net/ethernet/adi/bfin_mac.c
@@ -1719,7 +1719,6 @@ out_err_mii_probe:
mdiobus_unregister(lp->mii_bus);
mdiobus_free(lp->mii_bus);
out_err_probe_mac:
- platform_set_drvdata(pdev, NULL);
free_netdev(ndev);
return rc;
@@ -1732,8 +1731,6 @@ static int bfin_mac_remove(struct platform_device *pdev)
bfin_phc_release(lp);
- platform_set_drvdata(pdev, NULL);
-
lp->mii_bus->priv = NULL;
unregister_netdev(ndev);
@@ -1868,7 +1865,6 @@ static int bfin_mii_bus_remove(struct platform_device *pdev)
struct bfin_mii_bus_platform_data *mii_bus_pd =
dev_get_platdata(&pdev->dev);
- platform_set_drvdata(pdev, NULL);
mdiobus_unregister(miibus);
kfree(miibus->irq);
mdiobus_free(miibus);
diff --git a/drivers/net/ethernet/aeroflex/greth.c b/drivers/net/ethernet/aeroflex/greth.c
index 2692954..7ff4b30 100644
--- a/drivers/net/ethernet/aeroflex/greth.c
+++ b/drivers/net/ethernet/aeroflex/greth.c
@@ -1565,7 +1565,7 @@ error1:
static int greth_of_remove(struct platform_device *of_dev)
{
- struct net_device *ndev = dev_get_drvdata(&of_dev->dev);
+ struct net_device *ndev = platform_get_drvdata(of_dev);
struct greth_private *greth = netdev_priv(ndev);
/* Free descriptor areas */
@@ -1573,8 +1573,6 @@ static int greth_of_remove(struct platform_device *of_dev)
dma_free_coherent(&of_dev->dev, 1024, greth->tx_bd_base, greth->tx_bd_base_phys);
- dev_set_drvdata(&of_dev->dev, NULL);
-
if (greth->phy)
phy_stop(greth->phy);
mdiobus_unregister(greth->mdio);
diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig
new file mode 100644
index 0000000..53ad213
--- /dev/null
+++ b/drivers/net/ethernet/allwinner/Kconfig
@@ -0,0 +1,35 @@
+#
+# Allwinner device configuration
+#
+
+config NET_VENDOR_ALLWINNER
+ bool "Allwinner devices"
+ default y
+ depends on ARCH_SUNXI
+ ---help---
+ If you have a network (Ethernet) card belonging to this
+ class, say Y and read the Ethernet-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ Note that the answer to this question doesn't directly
+ affect the kernel: saying N will just cause the configurator
+ to skip all the questions about Allwinner cards. If you say Y,
+ you will be asked for your specific card in the following
+ questions.
+
+if NET_VENDOR_ALLWINNER
+
+config SUN4I_EMAC
+ tristate "Allwinner A10 EMAC support"
+ depends on ARCH_SUNXI
+ depends on OF
+ select CRC32
+ select MII
+ select PHYLIB
+ ---help---
+ Support for Allwinner A10 EMAC ethernet driver.
+
+ To compile this driver as a module, choose M here. The module
+ will be called sun4i-emac.
+
+endif # NET_VENDOR_ALLWINNER
diff --git a/drivers/net/ethernet/allwinner/Makefile b/drivers/net/ethernet/allwinner/Makefile
new file mode 100644
index 0000000..03129f7
--- /dev/null
+++ b/drivers/net/ethernet/allwinner/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Allwinner device drivers.
+#
+
+obj-$(CONFIG_SUN4I_EMAC) += sun4i-emac.o
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c
new file mode 100644
index 0000000..50b853a
--- /dev/null
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.c
@@ -0,0 +1,954 @@
+/*
+ * Allwinner EMAC Fast Ethernet driver for Linux.
+ *
+ * Copyright 2012-2013 Stefan Roese <sr@denx.de>
+ * Copyright 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * Based on the Linux driver provided by Allwinner:
+ * Copyright (C) 1997 Sten Wang
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+
+#include "sun4i-emac.h"
+
+#define DRV_NAME "sun4i-emac"
+#define DRV_VERSION "1.02"
+
+#define EMAC_MAX_FRAME_LEN 0x0600
+
+/* Transmit timeout, default 5 seconds. */
+static int watchdog = 5000;
+module_param(watchdog, int, 0400);
+MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
+
+/* EMAC register address locking.
+ *
+ * The EMAC uses an address register to control where data written
+ * to the data register goes. This means that the address register
+ * must be preserved over interrupts or similar calls.
+ *
+ * During interrupt and other critical calls, a spinlock is used to
+ * protect the system, but the calls themselves save the address
+ * in the address register in case they are interrupting another
+ * access to the device.
+ *
+ * For general accesses a lock is provided so that calls which are
+ * allowed to sleep are serialised so that the address register does
+ * not need to be saved. This lock also serves to serialise access
+ * to the EEPROM and PHY access registers which are shared between
+ * these two devices.
+ */
+
+/* The driver supports the original EMACE, and now the two newer
+ * devices, EMACA and EMACB.
+ */
+
+struct emac_board_info {
+ struct clk *clk;
+ struct device *dev;
+ struct platform_device *pdev;
+ spinlock_t lock;
+ void __iomem *membase;
+ u32 msg_enable;
+ struct net_device *ndev;
+ struct sk_buff *skb_last;
+ u16 tx_fifo_stat;
+
+ int emacrx_completed_flag;
+
+ struct phy_device *phy_dev;
+ struct device_node *phy_node;
+ unsigned int link;
+ unsigned int speed;
+ unsigned int duplex;
+
+ phy_interface_t phy_interface;
+};
+
+static void emac_update_speed(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+ unsigned int reg_val;
+
+ /* set EMAC SPEED, depend on PHY */
+ reg_val = readl(db->membase + EMAC_MAC_SUPP_REG);
+ reg_val &= ~(0x1 << 8);
+ if (db->speed == SPEED_100)
+ reg_val |= 1 << 8;
+ writel(reg_val, db->membase + EMAC_MAC_SUPP_REG);
+}
+
+static void emac_update_duplex(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+ unsigned int reg_val;
+
+ /* set duplex depend on phy */
+ reg_val = readl(db->membase + EMAC_MAC_CTL1_REG);
+ reg_val &= ~EMAC_MAC_CTL1_DUPLEX_EN;
+ if (db->duplex)
+ reg_val |= EMAC_MAC_CTL1_DUPLEX_EN;
+ writel(reg_val, db->membase + EMAC_MAC_CTL1_REG);
+}
+
+static void emac_handle_link_change(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+ struct phy_device *phydev = db->phy_dev;
+ unsigned long flags;
+ int status_change = 0;
+
+ if (phydev->link) {
+ if (db->speed != phydev->speed) {
+ spin_lock_irqsave(&db->lock, flags);
+ db->speed = phydev->speed;
+ emac_update_speed(dev);
+ spin_unlock_irqrestore(&db->lock, flags);
+ status_change = 1;
+ }
+
+ if (db->duplex != phydev->duplex) {
+ spin_lock_irqsave(&db->lock, flags);
+ db->duplex = phydev->duplex;
+ emac_update_duplex(dev);
+ spin_unlock_irqrestore(&db->lock, flags);
+ status_change = 1;
+ }
+ }
+
+ if (phydev->link != db->link) {
+ if (!phydev->link) {
+ db->speed = 0;
+ db->duplex = -1;
+ }
+ db->link = phydev->link;
+
+ status_change = 1;
+ }
+
+ if (status_change)
+ phy_print_status(phydev);
+}
+
+static int emac_mdio_probe(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+
+ /* to-do: PHY interrupts are currently not supported */
+
+ /* attach the mac to the phy */
+ db->phy_dev = of_phy_connect(db->ndev, db->phy_node,
+ &emac_handle_link_change, 0,
+ db->phy_interface);
+ if (!db->phy_dev) {
+ netdev_err(db->ndev, "could not find the PHY\n");
+ return -ENODEV;
+ }
+
+ /* mask with MAC supported features */
+ db->phy_dev->supported &= PHY_BASIC_FEATURES;
+ db->phy_dev->advertising = db->phy_dev->supported;
+
+ db->link = 0;
+ db->speed = 0;
+ db->duplex = -1;
+
+ return 0;
+}
+
+static void emac_mdio_remove(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+
+ phy_disconnect(db->phy_dev);
+ db->phy_dev = NULL;
+}
+
+static void emac_reset(struct emac_board_info *db)
+{
+ dev_dbg(db->dev, "resetting device\n");
+
+ /* RESET device */
+ writel(0, db->membase + EMAC_CTL_REG);
+ udelay(200);
+ writel(EMAC_CTL_RESET, db->membase + EMAC_CTL_REG);
+ udelay(200);
+}
+
+static void emac_outblk_32bit(void __iomem *reg, void *data, int count)
+{
+ writesl(reg, data, round_up(count, 4) / 4);
+}
+
+static void emac_inblk_32bit(void __iomem *reg, void *data, int count)
+{
+ readsl(reg, data, round_up(count, 4) / 4);
+}
+
+static int emac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct emac_board_info *dm = netdev_priv(dev);
+ struct phy_device *phydev = dm->phy_dev;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(phydev, rq, cmd);
+}
+
+/* ethtool ops */
+static void emac_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, DRV_NAME, sizeof(DRV_NAME));
+ strlcpy(info->version, DRV_VERSION, sizeof(DRV_VERSION));
+ strlcpy(info->bus_info, dev_name(&dev->dev), sizeof(info->bus_info));
+}
+
+static int emac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct emac_board_info *dm = netdev_priv(dev);
+ struct phy_device *phydev = dm->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_ethtool_gset(phydev, cmd);
+}
+
+static int emac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct emac_board_info *dm = netdev_priv(dev);
+ struct phy_device *phydev = dm->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(phydev, cmd);
+}
+
+static const struct ethtool_ops emac_ethtool_ops = {
+ .get_drvinfo = emac_get_drvinfo,
+ .get_settings = emac_get_settings,
+ .set_settings = emac_set_settings,
+ .get_link = ethtool_op_get_link,
+};
+
+static unsigned int emac_setup(struct net_device *ndev)
+{
+ struct emac_board_info *db = netdev_priv(ndev);
+ unsigned int reg_val;
+
+ /* set up TX */
+ reg_val = readl(db->membase + EMAC_TX_MODE_REG);
+
+ writel(reg_val | EMAC_TX_MODE_ABORTED_FRAME_EN,
+ db->membase + EMAC_TX_MODE_REG);
+
+ /* set up RX */
+ reg_val = readl(db->membase + EMAC_RX_CTL_REG);
+
+ writel(reg_val | EMAC_RX_CTL_PASS_LEN_OOR_EN |
+ EMAC_RX_CTL_ACCEPT_UNICAST_EN | EMAC_RX_CTL_DA_FILTER_EN |
+ EMAC_RX_CTL_ACCEPT_MULTICAST_EN |
+ EMAC_RX_CTL_ACCEPT_BROADCAST_EN,
+ db->membase + EMAC_RX_CTL_REG);
+
+ /* set MAC */
+ /* set MAC CTL0 */
+ reg_val = readl(db->membase + EMAC_MAC_CTL0_REG);
+ writel(reg_val | EMAC_MAC_CTL0_RX_FLOW_CTL_EN |
+ EMAC_MAC_CTL0_TX_FLOW_CTL_EN,
+ db->membase + EMAC_MAC_CTL0_REG);
+
+ /* set MAC CTL1 */
+ reg_val = readl(db->membase + EMAC_MAC_CTL1_REG);
+ reg_val |= EMAC_MAC_CTL1_LEN_CHECK_EN;
+ reg_val |= EMAC_MAC_CTL1_CRC_EN;
+ reg_val |= EMAC_MAC_CTL1_PAD_EN;
+ writel(reg_val, db->membase + EMAC_MAC_CTL1_REG);
+
+ /* set up IPGT */
+ writel(EMAC_MAC_IPGT_FULL_DUPLEX, db->membase + EMAC_MAC_IPGT_REG);
+
+ /* set up IPGR */
+ writel((EMAC_MAC_IPGR_IPG1 << 8) | EMAC_MAC_IPGR_IPG2,
+ db->membase + EMAC_MAC_IPGR_REG);
+
+ /* set up Collison window */
+ writel((EMAC_MAC_CLRT_COLLISION_WINDOW << 8) | EMAC_MAC_CLRT_RM,
+ db->membase + EMAC_MAC_CLRT_REG);
+
+ /* set up Max Frame Length */
+ writel(EMAC_MAX_FRAME_LEN,
+ db->membase + EMAC_MAC_MAXF_REG);
+
+ return 0;
+}
+
+static unsigned int emac_powerup(struct net_device *ndev)
+{
+ struct emac_board_info *db = netdev_priv(ndev);
+ unsigned int reg_val;
+
+ /* initial EMAC */
+ /* flush RX FIFO */
+ reg_val = readl(db->membase + EMAC_RX_CTL_REG);
+ reg_val |= 0x8;
+ writel(reg_val, db->membase + EMAC_RX_CTL_REG);
+ udelay(1);
+
+ /* initial MAC */
+ /* soft reset MAC */
+ reg_val = readl(db->membase + EMAC_MAC_CTL0_REG);
+ reg_val &= ~EMAC_MAC_CTL0_SOFT_RESET;
+ writel(reg_val, db->membase + EMAC_MAC_CTL0_REG);
+
+ /* set MII clock */
+ reg_val = readl(db->membase + EMAC_MAC_MCFG_REG);
+ reg_val &= (~(0xf << 2));
+ reg_val |= (0xD << 2);
+ writel(reg_val, db->membase + EMAC_MAC_MCFG_REG);
+
+ /* clear RX counter */
+ writel(0x0, db->membase + EMAC_RX_FBC_REG);
+
+ /* disable all interrupt and clear interrupt status */
+ writel(0, db->membase + EMAC_INT_CTL_REG);
+ reg_val = readl(db->membase + EMAC_INT_STA_REG);
+ writel(reg_val, db->membase + EMAC_INT_STA_REG);
+
+ udelay(1);
+
+ /* set up EMAC */
+ emac_setup(ndev);
+
+ /* set mac_address to chip */
+ writel(ndev->dev_addr[0] << 16 | ndev->dev_addr[1] << 8 | ndev->
+ dev_addr[2], db->membase + EMAC_MAC_A1_REG);
+ writel(ndev->dev_addr[3] << 16 | ndev->dev_addr[4] << 8 | ndev->
+ dev_addr[5], db->membase + EMAC_MAC_A0_REG);
+
+ mdelay(1);
+
+ return 0;
+}
+
+static int emac_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+ struct emac_board_info *db = netdev_priv(dev);
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+
+ writel(dev->dev_addr[0] << 16 | dev->dev_addr[1] << 8 | dev->
+ dev_addr[2], db->membase + EMAC_MAC_A1_REG);
+ writel(dev->dev_addr[3] << 16 | dev->dev_addr[4] << 8 | dev->
+ dev_addr[5], db->membase + EMAC_MAC_A0_REG);
+
+ return 0;
+}
+
+/* Initialize emac board */
+static void emac_init_device(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+ unsigned long flags;
+ unsigned int reg_val;
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ emac_update_speed(dev);
+ emac_update_duplex(dev);
+
+ /* enable RX/TX */
+ reg_val = readl(db->membase + EMAC_CTL_REG);
+ writel(reg_val | EMAC_CTL_RESET | EMAC_CTL_TX_EN | EMAC_CTL_RX_EN,
+ db->membase + EMAC_CTL_REG);
+
+ /* enable RX/TX0/RX Hlevel interrup */
+ reg_val = readl(db->membase + EMAC_INT_CTL_REG);
+ reg_val |= (0xf << 0) | (0x01 << 8);
+ writel(reg_val, db->membase + EMAC_INT_CTL_REG);
+
+ spin_unlock_irqrestore(&db->lock, flags);
+}
+
+/* Our watchdog timed out. Called by the networking layer */
+static void emac_timeout(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+ unsigned long flags;
+
+ if (netif_msg_timer(db))
+ dev_err(db->dev, "tx time out.\n");
+
+ /* Save previous register address */
+ spin_lock_irqsave(&db->lock, flags);
+
+ netif_stop_queue(dev);
+ emac_reset(db);
+ emac_init_device(dev);
+ /* We can accept TX packets again */
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+
+ /* Restore previous register address */
+ spin_unlock_irqrestore(&db->lock, flags);
+}
+
+/* Hardware start transmission.
+ * Send a packet to media from the upper layer.
+ */
+static int emac_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+ unsigned long channel;
+ unsigned long flags;
+
+ channel = db->tx_fifo_stat & 3;
+ if (channel == 3)
+ return 1;
+
+ channel = (channel == 1 ? 1 : 0);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ writel(channel, db->membase + EMAC_TX_INS_REG);
+
+ emac_outblk_32bit(db->membase + EMAC_TX_IO_DATA_REG,
+ skb->data, skb->len);
+ dev->stats.tx_bytes += skb->len;
+
+ db->tx_fifo_stat |= 1 << channel;
+ /* TX control: First packet immediately send, second packet queue */
+ if (channel == 0) {
+ /* set TX len */
+ writel(skb->len, db->membase + EMAC_TX_PL0_REG);
+ /* start translate from fifo to phy */
+ writel(readl(db->membase + EMAC_TX_CTL0_REG) | 1,
+ db->membase + EMAC_TX_CTL0_REG);
+
+ /* save the time stamp */
+ dev->trans_start = jiffies;
+ } else if (channel == 1) {
+ /* set TX len */
+ writel(skb->len, db->membase + EMAC_TX_PL1_REG);
+ /* start translate from fifo to phy */
+ writel(readl(db->membase + EMAC_TX_CTL1_REG) | 1,
+ db->membase + EMAC_TX_CTL1_REG);
+
+ /* save the time stamp */
+ dev->trans_start = jiffies;
+ }
+
+ if ((db->tx_fifo_stat & 3) == 3) {
+ /* Second packet */
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&db->lock, flags);
+
+ /* free this SKB */
+ dev_kfree_skb(skb);
+
+ return NETDEV_TX_OK;
+}
+
+/* EMAC interrupt handler
+ * receive the packet to upper layer, free the transmitted packet
+ */
+static void emac_tx_done(struct net_device *dev, struct emac_board_info *db,
+ unsigned int tx_status)
+{
+ /* One packet sent complete */
+ db->tx_fifo_stat &= ~(tx_status & 3);
+ if (3 == (tx_status & 3))
+ dev->stats.tx_packets += 2;
+ else
+ dev->stats.tx_packets++;
+
+ if (netif_msg_tx_done(db))
+ dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
+
+ netif_wake_queue(dev);
+}
+
+/* Received a packet and pass to upper layer
+ */
+static void emac_rx(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+ struct sk_buff *skb;
+ u8 *rdptr;
+ bool good_packet;
+ static int rxlen_last;
+ unsigned int reg_val;
+ u32 rxhdr, rxstatus, rxcount, rxlen;
+
+ /* Check packet ready or not */
+ while (1) {
+ /* race warning: the first packet might arrive with
+ * the interrupts disabled, but the second will fix
+ * it
+ */
+ rxcount = readl(db->membase + EMAC_RX_FBC_REG);
+
+ if (netif_msg_rx_status(db))
+ dev_dbg(db->dev, "RXCount: %x\n", rxcount);
+
+ if ((db->skb_last != NULL) && (rxlen_last > 0)) {
+ dev->stats.rx_bytes += rxlen_last;
+
+ /* Pass to upper layer */
+ db->skb_last->protocol = eth_type_trans(db->skb_last,
+ dev);
+ netif_rx(db->skb_last);
+ dev->stats.rx_packets++;
+ db->skb_last = NULL;
+ rxlen_last = 0;
+
+ reg_val = readl(db->membase + EMAC_RX_CTL_REG);
+ reg_val &= ~EMAC_RX_CTL_DMA_EN;
+ writel(reg_val, db->membase + EMAC_RX_CTL_REG);
+ }
+
+ if (!rxcount) {
+ db->emacrx_completed_flag = 1;
+ reg_val = readl(db->membase + EMAC_INT_CTL_REG);
+ reg_val |= (0xf << 0) | (0x01 << 8);
+ writel(reg_val, db->membase + EMAC_INT_CTL_REG);
+
+ /* had one stuck? */
+ rxcount = readl(db->membase + EMAC_RX_FBC_REG);
+ if (!rxcount)
+ return;
+ }
+
+ reg_val = readl(db->membase + EMAC_RX_IO_DATA_REG);
+ if (netif_msg_rx_status(db))
+ dev_dbg(db->dev, "receive header: %x\n", reg_val);
+ if (reg_val != EMAC_UNDOCUMENTED_MAGIC) {
+ /* disable RX */
+ reg_val = readl(db->membase + EMAC_CTL_REG);
+ writel(reg_val & ~EMAC_CTL_RX_EN,
+ db->membase + EMAC_CTL_REG);
+
+ /* Flush RX FIFO */
+ reg_val = readl(db->membase + EMAC_RX_CTL_REG);
+ writel(reg_val | (1 << 3),
+ db->membase + EMAC_RX_CTL_REG);
+
+ do {
+ reg_val = readl(db->membase + EMAC_RX_CTL_REG);
+ } while (reg_val & (1 << 3));
+
+ /* enable RX */
+ reg_val = readl(db->membase + EMAC_CTL_REG);
+ writel(reg_val | EMAC_CTL_RX_EN,
+ db->membase + EMAC_CTL_REG);
+ reg_val = readl(db->membase + EMAC_INT_CTL_REG);
+ reg_val |= (0xf << 0) | (0x01 << 8);
+ writel(reg_val, db->membase + EMAC_INT_CTL_REG);
+
+ db->emacrx_completed_flag = 1;
+
+ return;
+ }
+
+ /* A packet ready now & Get status/length */
+ good_packet = true;
+
+ emac_inblk_32bit(db->membase + EMAC_RX_IO_DATA_REG,
+ &rxhdr, sizeof(rxhdr));
+
+ if (netif_msg_rx_status(db))
+ dev_dbg(db->dev, "rxhdr: %x\n", *((int *)(&rxhdr)));
+
+ rxlen = EMAC_RX_IO_DATA_LEN(rxhdr);
+ rxstatus = EMAC_RX_IO_DATA_STATUS(rxhdr);
+
+ if (netif_msg_rx_status(db))
+ dev_dbg(db->dev, "RX: status %02x, length %04x\n",
+ rxstatus, rxlen);
+
+ /* Packet Status check */
+ if (rxlen < 0x40) {
+ good_packet = false;
+ if (netif_msg_rx_err(db))
+ dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
+ }
+
+ if (unlikely(!(rxstatus & EMAC_RX_IO_DATA_STATUS_OK))) {
+ good_packet = false;
+
+ if (rxstatus & EMAC_RX_IO_DATA_STATUS_CRC_ERR) {
+ if (netif_msg_rx_err(db))
+ dev_dbg(db->dev, "crc error\n");
+ dev->stats.rx_crc_errors++;
+ }
+
+ if (rxstatus & EMAC_RX_IO_DATA_STATUS_LEN_ERR) {
+ if (netif_msg_rx_err(db))
+ dev_dbg(db->dev, "length error\n");
+ dev->stats.rx_length_errors++;
+ }
+ }
+
+ /* Move data from EMAC */
+ skb = dev_alloc_skb(rxlen + 4);
+ if (good_packet && skb) {
+ skb_reserve(skb, 2);
+ rdptr = (u8 *) skb_put(skb, rxlen - 4);
+
+ /* Read received packet from RX SRAM */
+ if (netif_msg_rx_status(db))
+ dev_dbg(db->dev, "RxLen %x\n", rxlen);
+
+ emac_inblk_32bit(db->membase + EMAC_RX_IO_DATA_REG,
+ rdptr, rxlen);
+ dev->stats.rx_bytes += rxlen;
+
+ /* Pass to upper layer */
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ }
+ }
+}
+
+static irqreturn_t emac_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct emac_board_info *db = netdev_priv(dev);
+ int int_status;
+ unsigned long flags;
+ unsigned int reg_val;
+
+ /* A real interrupt coming */
+
+ /* holders of db->lock must always block IRQs */
+ spin_lock_irqsave(&db->lock, flags);
+
+ /* Disable all interrupts */
+ writel(0, db->membase + EMAC_INT_CTL_REG);
+
+ /* Got EMAC interrupt status */
+ /* Got ISR */
+ int_status = readl(db->membase + EMAC_INT_STA_REG);
+ /* Clear ISR status */
+ writel(int_status, db->membase + EMAC_INT_STA_REG);
+
+ if (netif_msg_intr(db))
+ dev_dbg(db->dev, "emac interrupt %02x\n", int_status);
+
+ /* Received the coming packet */
+ if ((int_status & 0x100) && (db->emacrx_completed_flag == 1)) {
+ /* carrier lost */
+ db->emacrx_completed_flag = 0;
+ emac_rx(dev);
+ }
+
+ /* Transmit Interrupt check */
+ if (int_status & (0x01 | 0x02))
+ emac_tx_done(dev, db, int_status);
+
+ if (int_status & (0x04 | 0x08))
+ netdev_info(dev, " ab : %x\n", int_status);
+
+ /* Re-enable interrupt mask */
+ if (db->emacrx_completed_flag == 1) {
+ reg_val = readl(db->membase + EMAC_INT_CTL_REG);
+ reg_val |= (0xf << 0) | (0x01 << 8);
+ writel(reg_val, db->membase + EMAC_INT_CTL_REG);
+ }
+ spin_unlock_irqrestore(&db->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Used by netconsole
+ */
+static void emac_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ emac_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+/* Open the interface.
+ * The interface is opened whenever "ifconfig" actives it.
+ */
+static int emac_open(struct net_device *dev)
+{
+ struct emac_board_info *db = netdev_priv(dev);
+ int ret;
+
+ if (netif_msg_ifup(db))
+ dev_dbg(db->dev, "enabling %s\n", dev->name);
+
+ if (devm_request_irq(db->dev, dev->irq, &emac_interrupt,
+ 0, dev->name, dev))
+ return -EAGAIN;
+
+ /* Initialize EMAC board */
+ emac_reset(db);
+ emac_init_device(dev);
+
+ ret = emac_mdio_probe(dev);
+ if (ret < 0) {
+ netdev_err(dev, "cannot probe MDIO bus\n");
+ return ret;
+ }
+
+ phy_start(db->phy_dev);
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static void emac_shutdown(struct net_device *dev)
+{
+ unsigned int reg_val;
+ struct emac_board_info *db = netdev_priv(dev);
+
+ /* Disable all interrupt */
+ writel(0, db->membase + EMAC_INT_CTL_REG);
+
+ /* clear interupt status */
+ reg_val = readl(db->membase + EMAC_INT_STA_REG);
+ writel(reg_val, db->membase + EMAC_INT_STA_REG);
+
+ /* Disable RX/TX */
+ reg_val = readl(db->membase + EMAC_CTL_REG);
+ reg_val &= ~(EMAC_CTL_TX_EN | EMAC_CTL_RX_EN | EMAC_CTL_RESET);
+ writel(reg_val, db->membase + EMAC_CTL_REG);
+}
+
+/* Stop the interface.
+ * The interface is stopped when it is brought.
+ */
+static int emac_stop(struct net_device *ndev)
+{
+ struct emac_board_info *db = netdev_priv(ndev);
+
+ if (netif_msg_ifdown(db))
+ dev_dbg(db->dev, "shutting down %s\n", ndev->name);
+
+ netif_stop_queue(ndev);
+ netif_carrier_off(ndev);
+
+ phy_stop(db->phy_dev);
+
+ emac_mdio_remove(ndev);
+
+ emac_shutdown(ndev);
+
+ return 0;
+}
+
+static const struct net_device_ops emac_netdev_ops = {
+ .ndo_open = emac_open,
+ .ndo_stop = emac_stop,
+ .ndo_start_xmit = emac_start_xmit,
+ .ndo_tx_timeout = emac_timeout,
+ .ndo_do_ioctl = emac_ioctl,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = emac_set_mac_address,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = emac_poll_controller,
+#endif
+};
+
+/* Search EMAC board, allocate space and register it
+ */
+static int emac_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct emac_board_info *db;
+ struct net_device *ndev;
+ int ret = 0;
+ const char *mac_addr;
+
+ ndev = alloc_etherdev(sizeof(struct emac_board_info));
+ if (!ndev) {
+ dev_err(&pdev->dev, "could not allocate device.\n");
+ return -ENOMEM;
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ db = netdev_priv(ndev);
+ memset(db, 0, sizeof(*db));
+
+ db->dev = &pdev->dev;
+ db->ndev = ndev;
+ db->pdev = pdev;
+
+ spin_lock_init(&db->lock);
+
+ db->membase = of_iomap(np, 0);
+ if (!db->membase) {
+ dev_err(&pdev->dev, "failed to remap registers\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* fill in parameters for net-dev structure */
+ ndev->base_addr = (unsigned long)db->membase;
+ ndev->irq = irq_of_parse_and_map(np, 0);
+ if (ndev->irq == -ENXIO) {
+ netdev_err(ndev, "No irq resource\n");
+ ret = ndev->irq;
+ goto out;
+ }
+
+ db->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(db->clk))
+ goto out;
+
+ clk_prepare_enable(db->clk);
+
+ db->phy_node = of_parse_phandle(np, "phy", 0);
+ if (!db->phy_node) {
+ dev_err(&pdev->dev, "no associated PHY\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Read MAC-address from DT */
+ mac_addr = of_get_mac_address(np);
+ if (mac_addr)
+ memcpy(ndev->dev_addr, mac_addr, ETH_ALEN);
+
+ /* Check if the MAC address is valid, if not get a random one */
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ eth_hw_addr_random(ndev);
+ dev_warn(&pdev->dev, "using random MAC address %pM\n",
+ ndev->dev_addr);
+ }
+
+ db->emacrx_completed_flag = 1;
+ emac_powerup(ndev);
+ emac_reset(db);
+
+ ether_setup(ndev);
+
+ ndev->netdev_ops = &emac_netdev_ops;
+ ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
+ ndev->ethtool_ops = &emac_ethtool_ops;
+
+ platform_set_drvdata(pdev, ndev);
+
+ /* Carrier starts down, phylib will bring it up */
+ netif_carrier_off(ndev);
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ dev_err(&pdev->dev, "Registering netdev failed!\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ dev_info(&pdev->dev, "%s: at %p, IRQ %d MAC: %pM\n",
+ ndev->name, db->membase, ndev->irq, ndev->dev_addr);
+
+ return 0;
+
+out:
+ dev_err(db->dev, "not found (%d).\n", ret);
+
+ free_netdev(ndev);
+
+ return ret;
+}
+
+static int emac_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+
+ dev_dbg(&pdev->dev, "released and freed device\n");
+ return 0;
+}
+
+static int emac_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct net_device *ndev = platform_get_drvdata(dev);
+
+ netif_carrier_off(ndev);
+ netif_device_detach(ndev);
+ emac_shutdown(ndev);
+
+ return 0;
+}
+
+static int emac_resume(struct platform_device *dev)
+{
+ struct net_device *ndev = platform_get_drvdata(dev);
+ struct emac_board_info *db = netdev_priv(ndev);
+
+ emac_reset(db);
+ emac_init_device(ndev);
+ netif_device_attach(ndev);
+
+ return 0;
+}
+
+static const struct of_device_id emac_of_match[] = {
+ {.compatible = "allwinner,sun4i-emac",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, emac_of_match);
+
+static struct platform_driver emac_driver = {
+ .driver = {
+ .name = "sun4i-emac",
+ .of_match_table = emac_of_match,
+ },
+ .probe = emac_probe,
+ .remove = emac_remove,
+ .suspend = emac_suspend,
+ .resume = emac_resume,
+};
+
+module_platform_driver(emac_driver);
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 emac network driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.h b/drivers/net/ethernet/allwinner/sun4i-emac.h
new file mode 100644
index 0000000..38c72d9
--- /dev/null
+++ b/drivers/net/ethernet/allwinner/sun4i-emac.h
@@ -0,0 +1,108 @@
+/*
+ * Allwinner EMAC Fast Ethernet driver for Linux.
+ *
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ * Copyright 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * Based on the Linux driver provided by Allwinner:
+ * Copyright (C) 1997 Sten Wang
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _SUN4I_EMAC_H_
+#define _SUN4I_EMAC_H_
+
+#define EMAC_CTL_REG (0x00)
+#define EMAC_CTL_RESET (1 << 0)
+#define EMAC_CTL_TX_EN (1 << 1)
+#define EMAC_CTL_RX_EN (1 << 2)
+#define EMAC_TX_MODE_REG (0x04)
+#define EMAC_TX_MODE_ABORTED_FRAME_EN (1 << 0)
+#define EMAC_TX_MODE_DMA_EN (1 << 1)
+#define EMAC_TX_FLOW_REG (0x08)
+#define EMAC_TX_CTL0_REG (0x0c)
+#define EMAC_TX_CTL1_REG (0x10)
+#define EMAC_TX_INS_REG (0x14)
+#define EMAC_TX_PL0_REG (0x18)
+#define EMAC_TX_PL1_REG (0x1c)
+#define EMAC_TX_STA_REG (0x20)
+#define EMAC_TX_IO_DATA_REG (0x24)
+#define EMAC_TX_IO_DATA1_REG (0x28)
+#define EMAC_TX_TSVL0_REG (0x2c)
+#define EMAC_TX_TSVH0_REG (0x30)
+#define EMAC_TX_TSVL1_REG (0x34)
+#define EMAC_TX_TSVH1_REG (0x38)
+#define EMAC_RX_CTL_REG (0x3c)
+#define EMAC_RX_CTL_AUTO_DRQ_EN (1 << 1)
+#define EMAC_RX_CTL_DMA_EN (1 << 2)
+#define EMAC_RX_CTL_PASS_ALL_EN (1 << 4)
+#define EMAC_RX_CTL_PASS_CTL_EN (1 << 5)
+#define EMAC_RX_CTL_PASS_CRC_ERR_EN (1 << 6)
+#define EMAC_RX_CTL_PASS_LEN_ERR_EN (1 << 7)
+#define EMAC_RX_CTL_PASS_LEN_OOR_EN (1 << 8)
+#define EMAC_RX_CTL_ACCEPT_UNICAST_EN (1 << 16)
+#define EMAC_RX_CTL_DA_FILTER_EN (1 << 17)
+#define EMAC_RX_CTL_ACCEPT_MULTICAST_EN (1 << 20)
+#define EMAC_RX_CTL_HASH_FILTER_EN (1 << 21)
+#define EMAC_RX_CTL_ACCEPT_BROADCAST_EN (1 << 22)
+#define EMAC_RX_CTL_SA_FILTER_EN (1 << 24)
+#define EMAC_RX_CTL_SA_FILTER_INVERT_EN (1 << 25)
+#define EMAC_RX_HASH0_REG (0x40)
+#define EMAC_RX_HASH1_REG (0x44)
+#define EMAC_RX_STA_REG (0x48)
+#define EMAC_RX_IO_DATA_REG (0x4c)
+#define EMAC_RX_IO_DATA_LEN(x) (x & 0xffff)
+#define EMAC_RX_IO_DATA_STATUS(x) ((x >> 16) & 0xffff)
+#define EMAC_RX_IO_DATA_STATUS_CRC_ERR (1 << 4)
+#define EMAC_RX_IO_DATA_STATUS_LEN_ERR (3 << 5)
+#define EMAC_RX_IO_DATA_STATUS_OK (1 << 7)
+#define EMAC_RX_FBC_REG (0x50)
+#define EMAC_INT_CTL_REG (0x54)
+#define EMAC_INT_STA_REG (0x58)
+#define EMAC_MAC_CTL0_REG (0x5c)
+#define EMAC_MAC_CTL0_RX_FLOW_CTL_EN (1 << 2)
+#define EMAC_MAC_CTL0_TX_FLOW_CTL_EN (1 << 3)
+#define EMAC_MAC_CTL0_SOFT_RESET (1 << 15)
+#define EMAC_MAC_CTL1_REG (0x60)
+#define EMAC_MAC_CTL1_DUPLEX_EN (1 << 0)
+#define EMAC_MAC_CTL1_LEN_CHECK_EN (1 << 1)
+#define EMAC_MAC_CTL1_HUGE_FRAME_EN (1 << 2)
+#define EMAC_MAC_CTL1_DELAYED_CRC_EN (1 << 3)
+#define EMAC_MAC_CTL1_CRC_EN (1 << 4)
+#define EMAC_MAC_CTL1_PAD_EN (1 << 5)
+#define EMAC_MAC_CTL1_PAD_CRC_EN (1 << 6)
+#define EMAC_MAC_CTL1_AD_SHORT_FRAME_EN (1 << 7)
+#define EMAC_MAC_CTL1_BACKOFF_DIS (1 << 12)
+#define EMAC_MAC_IPGT_REG (0x64)
+#define EMAC_MAC_IPGT_HALF_DUPLEX (0x12)
+#define EMAC_MAC_IPGT_FULL_DUPLEX (0x15)
+#define EMAC_MAC_IPGR_REG (0x68)
+#define EMAC_MAC_IPGR_IPG1 (0x0c)
+#define EMAC_MAC_IPGR_IPG2 (0x12)
+#define EMAC_MAC_CLRT_REG (0x6c)
+#define EMAC_MAC_CLRT_COLLISION_WINDOW (0x37)
+#define EMAC_MAC_CLRT_RM (0x0f)
+#define EMAC_MAC_MAXF_REG (0x70)
+#define EMAC_MAC_SUPP_REG (0x74)
+#define EMAC_MAC_TEST_REG (0x78)
+#define EMAC_MAC_MCFG_REG (0x7c)
+#define EMAC_MAC_A0_REG (0x98)
+#define EMAC_MAC_A1_REG (0x9c)
+#define EMAC_MAC_A2_REG (0xa0)
+#define EMAC_SAFX_L_REG0 (0xa4)
+#define EMAC_SAFX_H_REG0 (0xa8)
+#define EMAC_SAFX_L_REG1 (0xac)
+#define EMAC_SAFX_H_REG1 (0xb0)
+#define EMAC_SAFX_L_REG2 (0xb4)
+#define EMAC_SAFX_H_REG2 (0xb8)
+#define EMAC_SAFX_L_REG3 (0xbc)
+#define EMAC_SAFX_H_REG3 (0xc0)
+
+#define EMAC_PHY_DUPLEX (1 << 8)
+
+#define EMAC_EEPROM_MAGIC (0x444d394b)
+#define EMAC_UNDOCUMENTED_MAGIC (0x0143414d)
+#endif /* _SUN4I_EMAC_H_ */
diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c
index b7894f8..219be1b 100644
--- a/drivers/net/ethernet/alteon/acenic.c
+++ b/drivers/net/ethernet/alteon/acenic.c
@@ -702,19 +702,6 @@ static struct pci_driver acenic_pci_driver = {
.remove = acenic_remove_one,
};
-static int __init acenic_init(void)
-{
- return pci_register_driver(&acenic_pci_driver);
-}
-
-static void __exit acenic_exit(void)
-{
- pci_unregister_driver(&acenic_pci_driver);
-}
-
-module_init(acenic_init);
-module_exit(acenic_exit);
-
static void ace_free_descriptors(struct net_device *dev)
{
struct ace_private *ap = netdev_priv(dev);
@@ -3199,3 +3186,5 @@ static int read_eeprom_byte(struct net_device *dev, unsigned long offset)
ap->name, offset);
goto out;
}
+
+module_pci_driver(acenic_pci_driver);
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 13d74aa4..562df46 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -34,7 +34,6 @@ config AMD8111_ETH
tristate "AMD 8111 (new PCI LANCE) support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
If you have an AMD 8111-based PCI LANCE ethernet card,
@@ -60,7 +59,6 @@ config PCNET32
tristate "AMD PCnet32 PCI support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 8e6b665..1b1429d 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -1813,7 +1813,7 @@ static const struct net_device_ops amd8111e_netdev_ops = {
static int amd8111e_probe_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int err,i,pm_cap;
+ int err, i;
unsigned long reg_addr,reg_len;
struct amd8111e_priv* lp;
struct net_device* dev;
@@ -1842,7 +1842,7 @@ static int amd8111e_probe_one(struct pci_dev *pdev,
pci_set_master(pdev);
/* Find power-management capability. */
- if((pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM))==0){
+ if (!pdev->pm_cap) {
printk(KERN_ERR "amd8111e: No Power Management capability, "
"exiting.\n");
err = -ENODEV;
@@ -1875,7 +1875,7 @@ static int amd8111e_probe_one(struct pci_dev *pdev,
lp = netdev_priv(dev);
lp->pci_dev = pdev;
lp->amd8111e_net_dev = dev;
- lp->pm_cap = pm_cap;
+ lp->pm_cap = pdev->pm_cap;
spin_lock_init(&lp->lock);
@@ -1981,15 +1981,4 @@ static struct pci_driver amd8111e_driver = {
.resume = amd8111e_resume
};
-static int __init amd8111e_init(void)
-{
- return pci_register_driver(&amd8111e_driver);
-}
-
-static void __exit amd8111e_cleanup(void)
-{
- pci_unregister_driver(&amd8111e_driver);
-}
-
-module_init(amd8111e_init);
-module_exit(amd8111e_cleanup);
+module_pci_driver(amd8111e_driver);
diff --git a/drivers/net/ethernet/amd/au1000_eth.c b/drivers/net/ethernet/amd/au1000_eth.c
index 688aede..ceb45bc 100644
--- a/drivers/net/ethernet/amd/au1000_eth.c
+++ b/drivers/net/ethernet/amd/au1000_eth.c
@@ -1301,8 +1301,6 @@ static int au1000_remove(struct platform_device *pdev)
int i;
struct resource *base, *macen;
- platform_set_drvdata(pdev, NULL);
-
unregister_netdev(dev);
mdiobus_unregister(aup->mii_bus);
mdiobus_free(aup->mii_bus);
diff --git a/drivers/net/ethernet/amd/sunlance.c b/drivers/net/ethernet/amd/sunlance.c
index f47b780..ece5683 100644
--- a/drivers/net/ethernet/amd/sunlance.c
+++ b/drivers/net/ethernet/amd/sunlance.c
@@ -1470,7 +1470,7 @@ no_link_test:
goto fail;
}
- dev_set_drvdata(&op->dev, lp);
+ platform_set_drvdata(op, lp);
printk(KERN_INFO "%s: LANCE %pM\n",
dev->name, dev->dev_addr);
@@ -1501,7 +1501,7 @@ static int sunlance_sbus_probe(struct platform_device *op)
static int sunlance_sbus_remove(struct platform_device *op)
{
- struct lance_private *lp = dev_get_drvdata(&op->dev);
+ struct lance_private *lp = platform_get_drvdata(op);
struct net_device *net_dev = lp->dev;
unregister_netdev(net_dev);
@@ -1510,8 +1510,6 @@ static int sunlance_sbus_remove(struct platform_device *op)
free_netdev(net_dev);
- dev_set_drvdata(&op->dev, NULL);
-
return 0;
}
diff --git a/drivers/net/ethernet/apple/bmac.c b/drivers/net/ethernet/apple/bmac.c
index f36bbd6..714dcfe 100644
--- a/drivers/net/ethernet/apple/bmac.c
+++ b/drivers/net/ethernet/apple/bmac.c
@@ -1030,14 +1030,12 @@ static void bmac_set_multicast(struct net_device *dev)
rx_cfg |= RxPromiscEnable;
bmwrite(dev, RXCFG, rx_cfg);
} else {
- u16 hash_table[4];
+ u16 hash_table[4] = { 0 };
rx_cfg = bmread(dev, RXCFG);
rx_cfg &= ~RxPromiscEnable;
bmwrite(dev, RXCFG, rx_cfg);
- for(i = 0; i < 4; i++) hash_table[i] = 0;
-
netdev_for_each_mc_addr(ha, dev) {
crc = ether_crc_le(6, ha->addr);
crc >>= 26;
diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig
index 36d6abd..39e8d6c 100644
--- a/drivers/net/ethernet/atheros/Kconfig
+++ b/drivers/net/ethernet/atheros/Kconfig
@@ -22,7 +22,6 @@ config ATL2
tristate "Atheros L2 Fast Ethernet support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This driver supports the Atheros L2 fast ethernet adapter.
@@ -34,7 +33,6 @@ config ATL1
tristate "Atheros/Attansic L1 Gigabit Ethernet support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This driver supports the Atheros/Attansic L1 gigabit ethernet
@@ -47,7 +45,6 @@ config ATL1E
tristate "Atheros L1E Gigabit Ethernet support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This driver supports the Atheros L1E gigabit ethernet adapter.
@@ -59,7 +56,6 @@ config ATL1C
tristate "Atheros L1C Gigabit Ethernet support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This driver supports the Atheros L1C gigabit ethernet adapter.
@@ -67,4 +63,22 @@ config ATL1C
To compile this driver as a module, choose M here. The module
will be called atl1c.
+config ALX
+ tristate "Qualcomm Atheros AR816x/AR817x support"
+ depends on PCI
+ select CRC32
+ select NET_CORE
+ select MDIO
+ help
+ This driver supports the Qualcomm Atheros L1F ethernet adapter,
+ i.e. the following chipsets:
+
+ 1969:1091 - AR8161 Gigabit Ethernet
+ 1969:1090 - AR8162 Fast Ethernet
+ 1969:10A1 - AR8171 Gigabit Ethernet
+ 1969:10A0 - AR8172 Fast Ethernet
+
+ To compile this driver as a module, choose M here. The module
+ will be called alx.
+
endif # NET_VENDOR_ATHEROS
diff --git a/drivers/net/ethernet/atheros/Makefile b/drivers/net/ethernet/atheros/Makefile
index e7e76fb..5cf1c65 100644
--- a/drivers/net/ethernet/atheros/Makefile
+++ b/drivers/net/ethernet/atheros/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_ATL1) += atlx/
obj-$(CONFIG_ATL2) += atlx/
obj-$(CONFIG_ATL1E) += atl1e/
obj-$(CONFIG_ATL1C) += atl1c/
+obj-$(CONFIG_ALX) += alx/
diff --git a/drivers/net/ethernet/atheros/alx/Makefile b/drivers/net/ethernet/atheros/alx/Makefile
new file mode 100644
index 0000000..5901fa4
--- /dev/null
+++ b/drivers/net/ethernet/atheros/alx/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ALX) += alx.o
+alx-objs := main.o ethtool.o hw.o
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h
new file mode 100644
index 0000000..50b3ae2
--- /dev/null
+++ b/drivers/net/ethernet/atheros/alx/alx.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _ALX_H_
+#define _ALX_H_
+
+#include <linux/types.h>
+#include <linux/etherdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include "hw.h"
+
+#define ALX_WATCHDOG_TIME (5 * HZ)
+
+struct alx_buffer {
+ struct sk_buff *skb;
+ DEFINE_DMA_UNMAP_ADDR(dma);
+ DEFINE_DMA_UNMAP_LEN(size);
+};
+
+struct alx_rx_queue {
+ struct alx_rrd *rrd;
+ dma_addr_t rrd_dma;
+
+ struct alx_rfd *rfd;
+ dma_addr_t rfd_dma;
+
+ struct alx_buffer *bufs;
+
+ u16 write_idx, read_idx;
+ u16 rrd_read_idx;
+};
+#define ALX_RX_ALLOC_THRESH 32
+
+struct alx_tx_queue {
+ struct alx_txd *tpd;
+ dma_addr_t tpd_dma;
+ struct alx_buffer *bufs;
+ u16 write_idx, read_idx;
+};
+
+#define ALX_DEFAULT_TX_WORK 128
+
+enum alx_device_quirks {
+ ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG = BIT(0),
+};
+
+struct alx_priv {
+ struct net_device *dev;
+
+ struct alx_hw hw;
+
+ /* all descriptor memory */
+ struct {
+ dma_addr_t dma;
+ void *virt;
+ int size;
+ } descmem;
+
+ /* protect int_mask updates */
+ spinlock_t irq_lock;
+ u32 int_mask;
+
+ int tx_ringsz;
+ int rx_ringsz;
+ int rxbuf_size;
+
+ struct napi_struct napi;
+ struct alx_tx_queue txq;
+ struct alx_rx_queue rxq;
+
+ struct work_struct link_check_wk;
+ struct work_struct reset_wk;
+
+ u16 msg_enable;
+
+ bool msi;
+};
+
+extern const struct ethtool_ops alx_ethtool_ops;
+extern const char alx_drv_name[];
+
+#endif
diff --git a/drivers/net/ethernet/atheros/alx/ethtool.c b/drivers/net/ethernet/atheros/alx/ethtool.c
new file mode 100644
index 0000000..6fa2aec
--- /dev/null
+++ b/drivers/net/ethernet/atheros/alx/ethtool.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/pci.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mdio.h>
+#include <linux/interrupt.h>
+#include <asm/byteorder.h>
+
+#include "alx.h"
+#include "reg.h"
+#include "hw.h"
+
+
+static int alx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+
+ ecmd->supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_TP |
+ SUPPORTED_Pause;
+ if (alx_hw_giga(hw))
+ ecmd->supported |= SUPPORTED_1000baseT_Full;
+
+ ecmd->advertising = ADVERTISED_TP;
+ if (hw->adv_cfg & ADVERTISED_Autoneg)
+ ecmd->advertising |= hw->adv_cfg;
+
+ ecmd->port = PORT_TP;
+ ecmd->phy_address = 0;
+ if (hw->adv_cfg & ADVERTISED_Autoneg)
+ ecmd->autoneg = AUTONEG_ENABLE;
+ else
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->transceiver = XCVR_INTERNAL;
+
+ if (hw->flowctrl & ALX_FC_ANEG && hw->adv_cfg & ADVERTISED_Autoneg) {
+ if (hw->flowctrl & ALX_FC_RX) {
+ ecmd->advertising |= ADVERTISED_Pause;
+
+ if (!(hw->flowctrl & ALX_FC_TX))
+ ecmd->advertising |= ADVERTISED_Asym_Pause;
+ } else if (hw->flowctrl & ALX_FC_TX) {
+ ecmd->advertising |= ADVERTISED_Asym_Pause;
+ }
+ }
+
+ if (hw->link_speed != SPEED_UNKNOWN) {
+ ethtool_cmd_speed_set(ecmd,
+ hw->link_speed - hw->link_speed % 10);
+ ecmd->duplex = hw->link_speed % 10;
+ } else {
+ ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
+ ecmd->duplex = DUPLEX_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int alx_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+ u32 adv_cfg;
+
+ ASSERT_RTNL();
+
+ if (ecmd->autoneg == AUTONEG_ENABLE) {
+ if (ecmd->advertising & ADVERTISED_1000baseT_Half)
+ return -EINVAL;
+ adv_cfg = ecmd->advertising | ADVERTISED_Autoneg;
+ } else {
+ int speed = ethtool_cmd_speed(ecmd);
+
+ switch (speed + ecmd->duplex) {
+ case SPEED_10 + DUPLEX_HALF:
+ adv_cfg = ADVERTISED_10baseT_Half;
+ break;
+ case SPEED_10 + DUPLEX_FULL:
+ adv_cfg = ADVERTISED_10baseT_Full;
+ break;
+ case SPEED_100 + DUPLEX_HALF:
+ adv_cfg = ADVERTISED_100baseT_Half;
+ break;
+ case SPEED_100 + DUPLEX_FULL:
+ adv_cfg = ADVERTISED_100baseT_Full;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ hw->adv_cfg = adv_cfg;
+ return alx_setup_speed_duplex(hw, adv_cfg, hw->flowctrl);
+}
+
+static void alx_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+
+ if (hw->flowctrl & ALX_FC_ANEG &&
+ hw->adv_cfg & ADVERTISED_Autoneg)
+ pause->autoneg = AUTONEG_ENABLE;
+ else
+ pause->autoneg = AUTONEG_DISABLE;
+
+ if (hw->flowctrl & ALX_FC_TX)
+ pause->tx_pause = 1;
+ else
+ pause->tx_pause = 0;
+
+ if (hw->flowctrl & ALX_FC_RX)
+ pause->rx_pause = 1;
+ else
+ pause->rx_pause = 0;
+}
+
+
+static int alx_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+ int err = 0;
+ bool reconfig_phy = false;
+ u8 fc = 0;
+
+ if (pause->tx_pause)
+ fc |= ALX_FC_TX;
+ if (pause->rx_pause)
+ fc |= ALX_FC_RX;
+ if (pause->autoneg)
+ fc |= ALX_FC_ANEG;
+
+ ASSERT_RTNL();
+
+ /* restart auto-neg for auto-mode */
+ if (hw->adv_cfg & ADVERTISED_Autoneg) {
+ if (!((fc ^ hw->flowctrl) & ALX_FC_ANEG))
+ reconfig_phy = true;
+ if (fc & hw->flowctrl & ALX_FC_ANEG &&
+ (fc ^ hw->flowctrl) & (ALX_FC_RX | ALX_FC_TX))
+ reconfig_phy = true;
+ }
+
+ if (reconfig_phy) {
+ err = alx_setup_speed_duplex(hw, hw->adv_cfg, fc);
+ return err;
+ }
+
+ /* flow control on mac */
+ if ((fc ^ hw->flowctrl) & (ALX_FC_RX | ALX_FC_TX))
+ alx_cfg_mac_flowcontrol(hw, fc);
+
+ hw->flowctrl = fc;
+
+ return 0;
+}
+
+static u32 alx_get_msglevel(struct net_device *netdev)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+
+ return alx->msg_enable;
+}
+
+static void alx_set_msglevel(struct net_device *netdev, u32 data)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+
+ alx->msg_enable = data;
+}
+
+static void alx_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+
+ wol->supported = WAKE_MAGIC | WAKE_PHY;
+ wol->wolopts = 0;
+
+ if (hw->sleep_ctrl & ALX_SLEEP_WOL_MAGIC)
+ wol->wolopts |= WAKE_MAGIC;
+ if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY)
+ wol->wolopts |= WAKE_PHY;
+}
+
+static int alx_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+
+ if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
+ WAKE_UCAST | WAKE_BCAST | WAKE_MCAST))
+ return -EOPNOTSUPP;
+
+ hw->sleep_ctrl = 0;
+
+ if (wol->wolopts & WAKE_MAGIC)
+ hw->sleep_ctrl |= ALX_SLEEP_WOL_MAGIC;
+ if (wol->wolopts & WAKE_PHY)
+ hw->sleep_ctrl |= ALX_SLEEP_WOL_PHY;
+
+ device_set_wakeup_enable(&alx->hw.pdev->dev, hw->sleep_ctrl);
+
+ return 0;
+}
+
+static void alx_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+
+ strlcpy(drvinfo->driver, alx_drv_name, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->bus_info, pci_name(alx->hw.pdev),
+ sizeof(drvinfo->bus_info));
+}
+
+const struct ethtool_ops alx_ethtool_ops = {
+ .get_settings = alx_get_settings,
+ .set_settings = alx_set_settings,
+ .get_pauseparam = alx_get_pauseparam,
+ .set_pauseparam = alx_set_pauseparam,
+ .get_drvinfo = alx_get_drvinfo,
+ .get_msglevel = alx_get_msglevel,
+ .set_msglevel = alx_set_msglevel,
+ .get_wol = alx_get_wol,
+ .set_wol = alx_set_wol,
+ .get_link = ethtool_op_get_link,
+};
diff --git a/drivers/net/ethernet/atheros/alx/hw.c b/drivers/net/ethernet/atheros/alx/hw.c
new file mode 100644
index 0000000..220a16a
--- /dev/null
+++ b/drivers/net/ethernet/atheros/alx/hw.c
@@ -0,0 +1,1226 @@
+/*
+ * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/mdio.h>
+#include "reg.h"
+#include "hw.h"
+
+static inline bool alx_is_rev_a(u8 rev)
+{
+ return rev == ALX_REV_A0 || rev == ALX_REV_A1;
+}
+
+static int alx_wait_mdio_idle(struct alx_hw *hw)
+{
+ u32 val;
+ int i;
+
+ for (i = 0; i < ALX_MDIO_MAX_AC_TO; i++) {
+ val = alx_read_mem32(hw, ALX_MDIO);
+ if (!(val & ALX_MDIO_BUSY))
+ return 0;
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int alx_read_phy_core(struct alx_hw *hw, bool ext, u8 dev,
+ u16 reg, u16 *phy_data)
+{
+ u32 val, clk_sel;
+ int err;
+
+ *phy_data = 0;
+
+ /* use slow clock when it's in hibernation status */
+ clk_sel = hw->link_speed != SPEED_UNKNOWN ?
+ ALX_MDIO_CLK_SEL_25MD4 :
+ ALX_MDIO_CLK_SEL_25MD128;
+
+ if (ext) {
+ val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT |
+ reg << ALX_MDIO_EXTN_REG_SHIFT;
+ alx_write_mem32(hw, ALX_MDIO_EXTN, val);
+
+ val = ALX_MDIO_SPRES_PRMBL | ALX_MDIO_START |
+ ALX_MDIO_MODE_EXT | ALX_MDIO_OP_READ |
+ clk_sel << ALX_MDIO_CLK_SEL_SHIFT;
+ } else {
+ val = ALX_MDIO_SPRES_PRMBL |
+ clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
+ reg << ALX_MDIO_REG_SHIFT |
+ ALX_MDIO_START | ALX_MDIO_OP_READ;
+ }
+ alx_write_mem32(hw, ALX_MDIO, val);
+
+ err = alx_wait_mdio_idle(hw);
+ if (err)
+ return err;
+ val = alx_read_mem32(hw, ALX_MDIO);
+ *phy_data = ALX_GET_FIELD(val, ALX_MDIO_DATA);
+ return 0;
+}
+
+static int alx_write_phy_core(struct alx_hw *hw, bool ext, u8 dev,
+ u16 reg, u16 phy_data)
+{
+ u32 val, clk_sel;
+
+ /* use slow clock when it's in hibernation status */
+ clk_sel = hw->link_speed != SPEED_UNKNOWN ?
+ ALX_MDIO_CLK_SEL_25MD4 :
+ ALX_MDIO_CLK_SEL_25MD128;
+
+ if (ext) {
+ val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT |
+ reg << ALX_MDIO_EXTN_REG_SHIFT;
+ alx_write_mem32(hw, ALX_MDIO_EXTN, val);
+
+ val = ALX_MDIO_SPRES_PRMBL |
+ clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
+ phy_data << ALX_MDIO_DATA_SHIFT |
+ ALX_MDIO_START | ALX_MDIO_MODE_EXT;
+ } else {
+ val = ALX_MDIO_SPRES_PRMBL |
+ clk_sel << ALX_MDIO_CLK_SEL_SHIFT |
+ reg << ALX_MDIO_REG_SHIFT |
+ phy_data << ALX_MDIO_DATA_SHIFT |
+ ALX_MDIO_START;
+ }
+ alx_write_mem32(hw, ALX_MDIO, val);
+
+ return alx_wait_mdio_idle(hw);
+}
+
+static int __alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data)
+{
+ return alx_read_phy_core(hw, false, 0, reg, phy_data);
+}
+
+static int __alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data)
+{
+ return alx_write_phy_core(hw, false, 0, reg, phy_data);
+}
+
+static int __alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata)
+{
+ return alx_read_phy_core(hw, true, dev, reg, pdata);
+}
+
+static int __alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data)
+{
+ return alx_write_phy_core(hw, true, dev, reg, data);
+}
+
+static int __alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata)
+{
+ int err;
+
+ err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg);
+ if (err)
+ return err;
+
+ return __alx_read_phy_reg(hw, ALX_MII_DBG_DATA, pdata);
+}
+
+static int __alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data)
+{
+ int err;
+
+ err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg);
+ if (err)
+ return err;
+
+ return __alx_write_phy_reg(hw, ALX_MII_DBG_DATA, data);
+}
+
+int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data)
+{
+ int err;
+
+ spin_lock(&hw->mdio_lock);
+ err = __alx_read_phy_reg(hw, reg, phy_data);
+ spin_unlock(&hw->mdio_lock);
+
+ return err;
+}
+
+int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data)
+{
+ int err;
+
+ spin_lock(&hw->mdio_lock);
+ err = __alx_write_phy_reg(hw, reg, phy_data);
+ spin_unlock(&hw->mdio_lock);
+
+ return err;
+}
+
+int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata)
+{
+ int err;
+
+ spin_lock(&hw->mdio_lock);
+ err = __alx_read_phy_ext(hw, dev, reg, pdata);
+ spin_unlock(&hw->mdio_lock);
+
+ return err;
+}
+
+int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data)
+{
+ int err;
+
+ spin_lock(&hw->mdio_lock);
+ err = __alx_write_phy_ext(hw, dev, reg, data);
+ spin_unlock(&hw->mdio_lock);
+
+ return err;
+}
+
+static int alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata)
+{
+ int err;
+
+ spin_lock(&hw->mdio_lock);
+ err = __alx_read_phy_dbg(hw, reg, pdata);
+ spin_unlock(&hw->mdio_lock);
+
+ return err;
+}
+
+static int alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data)
+{
+ int err;
+
+ spin_lock(&hw->mdio_lock);
+ err = __alx_write_phy_dbg(hw, reg, data);
+ spin_unlock(&hw->mdio_lock);
+
+ return err;
+}
+
+static u16 alx_get_phy_config(struct alx_hw *hw)
+{
+ u32 val;
+ u16 phy_val;
+
+ val = alx_read_mem32(hw, ALX_PHY_CTRL);
+ /* phy in reset */
+ if ((val & ALX_PHY_CTRL_DSPRST_OUT) == 0)
+ return ALX_DRV_PHY_UNKNOWN;
+
+ val = alx_read_mem32(hw, ALX_DRV);
+ val = ALX_GET_FIELD(val, ALX_DRV_PHY);
+ if (ALX_DRV_PHY_UNKNOWN == val)
+ return ALX_DRV_PHY_UNKNOWN;
+
+ alx_read_phy_reg(hw, ALX_MII_DBG_ADDR, &phy_val);
+ if (ALX_PHY_INITED == phy_val)
+ return val;
+
+ return ALX_DRV_PHY_UNKNOWN;
+}
+
+static bool alx_wait_reg(struct alx_hw *hw, u32 reg, u32 wait, u32 *val)
+{
+ u32 read;
+ int i;
+
+ for (i = 0; i < ALX_SLD_MAX_TO; i++) {
+ read = alx_read_mem32(hw, reg);
+ if ((read & wait) == 0) {
+ if (val)
+ *val = read;
+ return true;
+ }
+ mdelay(1);
+ }
+
+ return false;
+}
+
+static bool alx_read_macaddr(struct alx_hw *hw, u8 *addr)
+{
+ u32 mac0, mac1;
+
+ mac0 = alx_read_mem32(hw, ALX_STAD0);
+ mac1 = alx_read_mem32(hw, ALX_STAD1);
+
+ /* addr should be big-endian */
+ *(__be32 *)(addr + 2) = cpu_to_be32(mac0);
+ *(__be16 *)addr = cpu_to_be16(mac1);
+
+ return is_valid_ether_addr(addr);
+}
+
+int alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr)
+{
+ u32 val;
+
+ /* try to get it from register first */
+ if (alx_read_macaddr(hw, addr))
+ return 0;
+
+ /* try to load from efuse */
+ if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_STAT | ALX_SLD_START, &val))
+ return -EIO;
+ alx_write_mem32(hw, ALX_SLD, val | ALX_SLD_START);
+ if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_START, NULL))
+ return -EIO;
+ if (alx_read_macaddr(hw, addr))
+ return 0;
+
+ /* try to load from flash/eeprom (if present) */
+ val = alx_read_mem32(hw, ALX_EFLD);
+ if (val & (ALX_EFLD_F_EXIST | ALX_EFLD_E_EXIST)) {
+ if (!alx_wait_reg(hw, ALX_EFLD,
+ ALX_EFLD_STAT | ALX_EFLD_START, &val))
+ return -EIO;
+ alx_write_mem32(hw, ALX_EFLD, val | ALX_EFLD_START);
+ if (!alx_wait_reg(hw, ALX_EFLD, ALX_EFLD_START, NULL))
+ return -EIO;
+ if (alx_read_macaddr(hw, addr))
+ return 0;
+ }
+
+ return -EIO;
+}
+
+void alx_set_macaddr(struct alx_hw *hw, const u8 *addr)
+{
+ u32 val;
+
+ /* for example: 00-0B-6A-F6-00-DC * STAD0=6AF600DC, STAD1=000B */
+ val = be32_to_cpu(*(__be32 *)(addr + 2));
+ alx_write_mem32(hw, ALX_STAD0, val);
+ val = be16_to_cpu(*(__be16 *)addr);
+ alx_write_mem32(hw, ALX_STAD1, val);
+}
+
+static void alx_enable_osc(struct alx_hw *hw)
+{
+ u32 val;
+
+ /* rising edge */
+ val = alx_read_mem32(hw, ALX_MISC);
+ alx_write_mem32(hw, ALX_MISC, val & ~ALX_MISC_INTNLOSC_OPEN);
+ alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
+}
+
+static void alx_reset_osc(struct alx_hw *hw, u8 rev)
+{
+ u32 val, val2;
+
+ /* clear Internal OSC settings, switching OSC by hw itself */
+ val = alx_read_mem32(hw, ALX_MISC3);
+ alx_write_mem32(hw, ALX_MISC3,
+ (val & ~ALX_MISC3_25M_BY_SW) |
+ ALX_MISC3_25M_NOTO_INTNL);
+
+ /* 25M clk from chipset may be unstable 1s after de-assert of
+ * PERST, driver need re-calibrate before enter Sleep for WoL
+ */
+ val = alx_read_mem32(hw, ALX_MISC);
+ if (rev >= ALX_REV_B0) {
+ /* restore over current protection def-val,
+ * this val could be reset by MAC-RST
+ */
+ ALX_SET_FIELD(val, ALX_MISC_PSW_OCP, ALX_MISC_PSW_OCP_DEF);
+ /* a 0->1 change will update the internal val of osc */
+ val &= ~ALX_MISC_INTNLOSC_OPEN;
+ alx_write_mem32(hw, ALX_MISC, val);
+ alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
+ /* hw will automatically dis OSC after cab. */
+ val2 = alx_read_mem32(hw, ALX_MSIC2);
+ val2 &= ~ALX_MSIC2_CALB_START;
+ alx_write_mem32(hw, ALX_MSIC2, val2);
+ alx_write_mem32(hw, ALX_MSIC2, val2 | ALX_MSIC2_CALB_START);
+ } else {
+ val &= ~ALX_MISC_INTNLOSC_OPEN;
+ /* disable isolate for rev A devices */
+ if (alx_is_rev_a(rev))
+ val &= ~ALX_MISC_ISO_EN;
+
+ alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN);
+ alx_write_mem32(hw, ALX_MISC, val);
+ }
+
+ udelay(20);
+}
+
+static int alx_stop_mac(struct alx_hw *hw)
+{
+ u32 rxq, txq, val;
+ u16 i;
+
+ rxq = alx_read_mem32(hw, ALX_RXQ0);
+ alx_write_mem32(hw, ALX_RXQ0, rxq & ~ALX_RXQ0_EN);
+ txq = alx_read_mem32(hw, ALX_TXQ0);
+ alx_write_mem32(hw, ALX_TXQ0, txq & ~ALX_TXQ0_EN);
+
+ udelay(40);
+
+ hw->rx_ctrl &= ~(ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN);
+ alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+
+ for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) {
+ val = alx_read_mem32(hw, ALX_MAC_STS);
+ if (!(val & ALX_MAC_STS_IDLE))
+ return 0;
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+int alx_reset_mac(struct alx_hw *hw)
+{
+ u32 val, pmctrl;
+ int i, ret;
+ u8 rev;
+ bool a_cr;
+
+ pmctrl = 0;
+ rev = alx_hw_revision(hw);
+ a_cr = alx_is_rev_a(rev) && alx_hw_with_cr(hw);
+
+ /* disable all interrupts, RXQ/TXQ */
+ alx_write_mem32(hw, ALX_MSIX_MASK, 0xFFFFFFFF);
+ alx_write_mem32(hw, ALX_IMR, 0);
+ alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS);
+
+ ret = alx_stop_mac(hw);
+ if (ret)
+ return ret;
+
+ /* mac reset workaroud */
+ alx_write_mem32(hw, ALX_RFD_PIDX, 1);
+
+ /* dis l0s/l1 before mac reset */
+ if (a_cr) {
+ pmctrl = alx_read_mem32(hw, ALX_PMCTRL);
+ if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN))
+ alx_write_mem32(hw, ALX_PMCTRL,
+ pmctrl & ~(ALX_PMCTRL_L1_EN |
+ ALX_PMCTRL_L0S_EN));
+ }
+
+ /* reset whole mac safely */
+ val = alx_read_mem32(hw, ALX_MASTER);
+ alx_write_mem32(hw, ALX_MASTER,
+ val | ALX_MASTER_DMA_MAC_RST | ALX_MASTER_OOB_DIS);
+
+ /* make sure it's real idle */
+ udelay(10);
+ for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) {
+ val = alx_read_mem32(hw, ALX_RFD_PIDX);
+ if (val == 0)
+ break;
+ udelay(10);
+ }
+ for (; i < ALX_DMA_MAC_RST_TO; i++) {
+ val = alx_read_mem32(hw, ALX_MASTER);
+ if ((val & ALX_MASTER_DMA_MAC_RST) == 0)
+ break;
+ udelay(10);
+ }
+ if (i == ALX_DMA_MAC_RST_TO)
+ return -EIO;
+ udelay(10);
+
+ if (a_cr) {
+ alx_write_mem32(hw, ALX_MASTER, val | ALX_MASTER_PCLKSEL_SRDS);
+ /* restore l0s / l1 */
+ if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN))
+ alx_write_mem32(hw, ALX_PMCTRL, pmctrl);
+ }
+
+ alx_reset_osc(hw, rev);
+
+ /* clear Internal OSC settings, switching OSC by hw itself,
+ * disable isolate for rev A devices
+ */
+ val = alx_read_mem32(hw, ALX_MISC3);
+ alx_write_mem32(hw, ALX_MISC3,
+ (val & ~ALX_MISC3_25M_BY_SW) |
+ ALX_MISC3_25M_NOTO_INTNL);
+ val = alx_read_mem32(hw, ALX_MISC);
+ val &= ~ALX_MISC_INTNLOSC_OPEN;
+ if (alx_is_rev_a(rev))
+ val &= ~ALX_MISC_ISO_EN;
+ alx_write_mem32(hw, ALX_MISC, val);
+ udelay(20);
+
+ /* driver control speed/duplex, hash-alg */
+ alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+
+ val = alx_read_mem32(hw, ALX_SERDES);
+ alx_write_mem32(hw, ALX_SERDES,
+ val | ALX_SERDES_MACCLK_SLWDWN |
+ ALX_SERDES_PHYCLK_SLWDWN);
+
+ return 0;
+}
+
+void alx_reset_phy(struct alx_hw *hw)
+{
+ int i;
+ u32 val;
+ u16 phy_val;
+
+ /* (DSP)reset PHY core */
+ val = alx_read_mem32(hw, ALX_PHY_CTRL);
+ val &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_IDDQ |
+ ALX_PHY_CTRL_GATE_25M | ALX_PHY_CTRL_POWER_DOWN |
+ ALX_PHY_CTRL_CLS);
+ val |= ALX_PHY_CTRL_RST_ANALOG;
+
+ val |= (ALX_PHY_CTRL_HIB_PULSE | ALX_PHY_CTRL_HIB_EN);
+ alx_write_mem32(hw, ALX_PHY_CTRL, val);
+ udelay(10);
+ alx_write_mem32(hw, ALX_PHY_CTRL, val | ALX_PHY_CTRL_DSPRST_OUT);
+
+ for (i = 0; i < ALX_PHY_CTRL_DSPRST_TO; i++)
+ udelay(10);
+
+ /* phy power saving & hib */
+ alx_write_phy_dbg(hw, ALX_MIIDBG_LEGCYPS, ALX_LEGCYPS_DEF);
+ alx_write_phy_dbg(hw, ALX_MIIDBG_SYSMODCTRL,
+ ALX_SYSMODCTRL_IECHOADJ_DEF);
+ alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_VDRVBIAS,
+ ALX_VDRVBIAS_DEF);
+
+ /* EEE advertisement */
+ val = alx_read_mem32(hw, ALX_LPI_CTRL);
+ alx_write_mem32(hw, ALX_LPI_CTRL, val & ~ALX_LPI_CTRL_EN);
+ alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_LOCAL_EEEADV, 0);
+
+ /* phy power saving */
+ alx_write_phy_dbg(hw, ALX_MIIDBG_TST10BTCFG, ALX_TST10BTCFG_DEF);
+ alx_write_phy_dbg(hw, ALX_MIIDBG_SRDSYSMOD, ALX_SRDSYSMOD_DEF);
+ alx_write_phy_dbg(hw, ALX_MIIDBG_TST100BTCFG, ALX_TST100BTCFG_DEF);
+ alx_write_phy_dbg(hw, ALX_MIIDBG_ANACTRL, ALX_ANACTRL_DEF);
+ alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val);
+ alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2,
+ phy_val & ~ALX_GREENCFG2_GATE_DFSE_EN);
+ /* rtl8139c, 120m issue */
+ alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_NLP78,
+ ALX_MIIEXT_NLP78_120M_DEF);
+ alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_S3DIG10,
+ ALX_MIIEXT_S3DIG10_DEF);
+
+ if (hw->lnk_patch) {
+ /* Turn off half amplitude */
+ alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3,
+ &phy_val);
+ alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3,
+ phy_val | ALX_CLDCTRL3_BP_CABLE1TH_DET_GT);
+ /* Turn off Green feature */
+ alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val);
+ alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2,
+ phy_val | ALX_GREENCFG2_BP_GREEN);
+ /* Turn off half Bias */
+ alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5,
+ &phy_val);
+ alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5,
+ phy_val | ALX_CLDCTRL5_BP_VD_HLFBIAS);
+ }
+
+ /* set phy interrupt mask */
+ alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP | ALX_IER_LINK_DOWN);
+}
+
+#define ALX_PCI_CMD (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO)
+
+void alx_reset_pcie(struct alx_hw *hw)
+{
+ u8 rev = alx_hw_revision(hw);
+ u32 val;
+ u16 val16;
+
+ /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */
+ pci_read_config_word(hw->pdev, PCI_COMMAND, &val16);
+ if (!(val16 & ALX_PCI_CMD) || (val16 & PCI_COMMAND_INTX_DISABLE)) {
+ val16 = (val16 | ALX_PCI_CMD) & ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(hw->pdev, PCI_COMMAND, val16);
+ }
+
+ /* clear WoL setting/status */
+ val = alx_read_mem32(hw, ALX_WOL0);
+ alx_write_mem32(hw, ALX_WOL0, 0);
+
+ val = alx_read_mem32(hw, ALX_PDLL_TRNS1);
+ alx_write_mem32(hw, ALX_PDLL_TRNS1, val & ~ALX_PDLL_TRNS1_D3PLLOFF_EN);
+
+ /* mask some pcie error bits */
+ val = alx_read_mem32(hw, ALX_UE_SVRT);
+ val &= ~(ALX_UE_SVRT_DLPROTERR | ALX_UE_SVRT_FCPROTERR);
+ alx_write_mem32(hw, ALX_UE_SVRT, val);
+
+ /* wol 25M & pclk */
+ val = alx_read_mem32(hw, ALX_MASTER);
+ if (alx_is_rev_a(rev) && alx_hw_with_cr(hw)) {
+ if ((val & ALX_MASTER_WAKEN_25M) == 0 ||
+ (val & ALX_MASTER_PCLKSEL_SRDS) == 0)
+ alx_write_mem32(hw, ALX_MASTER,
+ val | ALX_MASTER_PCLKSEL_SRDS |
+ ALX_MASTER_WAKEN_25M);
+ } else {
+ if ((val & ALX_MASTER_WAKEN_25M) == 0 ||
+ (val & ALX_MASTER_PCLKSEL_SRDS) != 0)
+ alx_write_mem32(hw, ALX_MASTER,
+ (val & ~ALX_MASTER_PCLKSEL_SRDS) |
+ ALX_MASTER_WAKEN_25M);
+ }
+
+ /* ASPM setting */
+ alx_enable_aspm(hw, true, true);
+
+ udelay(10);
+}
+
+void alx_start_mac(struct alx_hw *hw)
+{
+ u32 mac, txq, rxq;
+
+ rxq = alx_read_mem32(hw, ALX_RXQ0);
+ alx_write_mem32(hw, ALX_RXQ0, rxq | ALX_RXQ0_EN);
+ txq = alx_read_mem32(hw, ALX_TXQ0);
+ alx_write_mem32(hw, ALX_TXQ0, txq | ALX_TXQ0_EN);
+
+ mac = hw->rx_ctrl;
+ if (hw->link_speed % 10 == DUPLEX_FULL)
+ mac |= ALX_MAC_CTRL_FULLD;
+ else
+ mac &= ~ALX_MAC_CTRL_FULLD;
+ ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,
+ hw->link_speed >= SPEED_1000 ? ALX_MAC_CTRL_SPEED_1000 :
+ ALX_MAC_CTRL_SPEED_10_100);
+ mac |= ALX_MAC_CTRL_TX_EN | ALX_MAC_CTRL_RX_EN;
+ hw->rx_ctrl = mac;
+ alx_write_mem32(hw, ALX_MAC_CTRL, mac);
+}
+
+void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc)
+{
+ if (fc & ALX_FC_RX)
+ hw->rx_ctrl |= ALX_MAC_CTRL_RXFC_EN;
+ else
+ hw->rx_ctrl &= ~ALX_MAC_CTRL_RXFC_EN;
+
+ if (fc & ALX_FC_TX)
+ hw->rx_ctrl |= ALX_MAC_CTRL_TXFC_EN;
+ else
+ hw->rx_ctrl &= ~ALX_MAC_CTRL_TXFC_EN;
+
+ alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+}
+
+void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en)
+{
+ u32 pmctrl;
+ u8 rev = alx_hw_revision(hw);
+
+ pmctrl = alx_read_mem32(hw, ALX_PMCTRL);
+
+ ALX_SET_FIELD(pmctrl, ALX_PMCTRL_LCKDET_TIMER,
+ ALX_PMCTRL_LCKDET_TIMER_DEF);
+ pmctrl |= ALX_PMCTRL_RCVR_WT_1US |
+ ALX_PMCTRL_L1_CLKSW_EN |
+ ALX_PMCTRL_L1_SRDSRX_PWD;
+ ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1REQ_TO, ALX_PMCTRL_L1REG_TO_DEF);
+ ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1_TIMER, ALX_PMCTRL_L1_TIMER_16US);
+ pmctrl &= ~(ALX_PMCTRL_L1_SRDS_EN |
+ ALX_PMCTRL_L1_SRDSPLL_EN |
+ ALX_PMCTRL_L1_BUFSRX_EN |
+ ALX_PMCTRL_SADLY_EN |
+ ALX_PMCTRL_HOTRST_WTEN|
+ ALX_PMCTRL_L0S_EN |
+ ALX_PMCTRL_L1_EN |
+ ALX_PMCTRL_ASPM_FCEN |
+ ALX_PMCTRL_TXL1_AFTER_L0S |
+ ALX_PMCTRL_RXL1_AFTER_L0S);
+ if (alx_is_rev_a(rev) && alx_hw_with_cr(hw))
+ pmctrl |= ALX_PMCTRL_L1_SRDS_EN | ALX_PMCTRL_L1_SRDSPLL_EN;
+
+ if (l0s_en)
+ pmctrl |= (ALX_PMCTRL_L0S_EN | ALX_PMCTRL_ASPM_FCEN);
+ if (l1_en)
+ pmctrl |= (ALX_PMCTRL_L1_EN | ALX_PMCTRL_ASPM_FCEN);
+
+ alx_write_mem32(hw, ALX_PMCTRL, pmctrl);
+}
+
+
+static u32 ethadv_to_hw_cfg(struct alx_hw *hw, u32 ethadv_cfg)
+{
+ u32 cfg = 0;
+
+ if (ethadv_cfg & ADVERTISED_Autoneg) {
+ cfg |= ALX_DRV_PHY_AUTO;
+ if (ethadv_cfg & ADVERTISED_10baseT_Half)
+ cfg |= ALX_DRV_PHY_10;
+ if (ethadv_cfg & ADVERTISED_10baseT_Full)
+ cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX;
+ if (ethadv_cfg & ADVERTISED_100baseT_Half)
+ cfg |= ALX_DRV_PHY_100;
+ if (ethadv_cfg & ADVERTISED_100baseT_Full)
+ cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
+ if (ethadv_cfg & ADVERTISED_1000baseT_Half)
+ cfg |= ALX_DRV_PHY_1000;
+ if (ethadv_cfg & ADVERTISED_1000baseT_Full)
+ cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
+ if (ethadv_cfg & ADVERTISED_Pause)
+ cfg |= ADVERTISE_PAUSE_CAP;
+ if (ethadv_cfg & ADVERTISED_Asym_Pause)
+ cfg |= ADVERTISE_PAUSE_ASYM;
+ } else {
+ switch (ethadv_cfg) {
+ case ADVERTISED_10baseT_Half:
+ cfg |= ALX_DRV_PHY_10;
+ break;
+ case ADVERTISED_100baseT_Half:
+ cfg |= ALX_DRV_PHY_100;
+ break;
+ case ADVERTISED_10baseT_Full:
+ cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX;
+ break;
+ case ADVERTISED_100baseT_Full:
+ cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX;
+ break;
+ }
+ }
+
+ return cfg;
+}
+
+int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl)
+{
+ u16 adv, giga, cr;
+ u32 val;
+ int err = 0;
+
+ alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, 0);
+ val = alx_read_mem32(hw, ALX_DRV);
+ ALX_SET_FIELD(val, ALX_DRV_PHY, 0);
+
+ if (ethadv & ADVERTISED_Autoneg) {
+ adv = ADVERTISE_CSMA;
+ adv |= ethtool_adv_to_mii_adv_t(ethadv);
+
+ if (flowctrl & ALX_FC_ANEG) {
+ if (flowctrl & ALX_FC_RX) {
+ adv |= ADVERTISED_Pause;
+ if (!(flowctrl & ALX_FC_TX))
+ adv |= ADVERTISED_Asym_Pause;
+ } else if (flowctrl & ALX_FC_TX) {
+ adv |= ADVERTISED_Asym_Pause;
+ }
+ }
+ giga = 0;
+ if (alx_hw_giga(hw))
+ giga = ethtool_adv_to_mii_ctrl1000_t(ethadv);
+
+ cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART;
+
+ if (alx_write_phy_reg(hw, MII_ADVERTISE, adv) ||
+ alx_write_phy_reg(hw, MII_CTRL1000, giga) ||
+ alx_write_phy_reg(hw, MII_BMCR, cr))
+ err = -EBUSY;
+ } else {
+ cr = BMCR_RESET;
+ if (ethadv == ADVERTISED_100baseT_Half ||
+ ethadv == ADVERTISED_100baseT_Full)
+ cr |= BMCR_SPEED100;
+ if (ethadv == ADVERTISED_10baseT_Full ||
+ ethadv == ADVERTISED_100baseT_Full)
+ cr |= BMCR_FULLDPLX;
+
+ err = alx_write_phy_reg(hw, MII_BMCR, cr);
+ }
+
+ if (!err) {
+ alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, ALX_PHY_INITED);
+ val |= ethadv_to_hw_cfg(hw, ethadv);
+ }
+
+ alx_write_mem32(hw, ALX_DRV, val);
+
+ return err;
+}
+
+
+void alx_post_phy_link(struct alx_hw *hw)
+{
+ u16 phy_val, len, agc;
+ u8 revid = alx_hw_revision(hw);
+ bool adj_th = revid == ALX_REV_B0;
+ int speed;
+
+ if (hw->link_speed == SPEED_UNKNOWN)
+ speed = SPEED_UNKNOWN;
+ else
+ speed = hw->link_speed - hw->link_speed % 10;
+
+ if (revid != ALX_REV_B0 && !alx_is_rev_a(revid))
+ return;
+
+ /* 1000BT/AZ, wrong cable length */
+ if (speed != SPEED_UNKNOWN) {
+ alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL6,
+ &phy_val);
+ len = ALX_GET_FIELD(phy_val, ALX_CLDCTRL6_CAB_LEN);
+ alx_read_phy_dbg(hw, ALX_MIIDBG_AGC, &phy_val);
+ agc = ALX_GET_FIELD(phy_val, ALX_AGC_2_VGA);
+
+ if ((speed == SPEED_1000 &&
+ (len > ALX_CLDCTRL6_CAB_LEN_SHORT1G ||
+ (len == 0 && agc > ALX_AGC_LONG1G_LIMT))) ||
+ (speed == SPEED_100 &&
+ (len > ALX_CLDCTRL6_CAB_LEN_SHORT100M ||
+ (len == 0 && agc > ALX_AGC_LONG100M_LIMT)))) {
+ alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT,
+ ALX_AZ_ANADECT_LONG);
+ alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+ &phy_val);
+ alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+ phy_val | ALX_AFE_10BT_100M_TH);
+ } else {
+ alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT,
+ ALX_AZ_ANADECT_DEF);
+ alx_read_phy_ext(hw, ALX_MIIEXT_ANEG,
+ ALX_MIIEXT_AFE, &phy_val);
+ alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+ phy_val & ~ALX_AFE_10BT_100M_TH);
+ }
+
+ /* threshold adjust */
+ if (adj_th && hw->lnk_patch) {
+ if (speed == SPEED_100) {
+ alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB,
+ ALX_MSE16DB_UP);
+ } else if (speed == SPEED_1000) {
+ /*
+ * Giga link threshold, raise the tolerance of
+ * noise 50%
+ */
+ alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB,
+ &phy_val);
+ ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH,
+ ALX_MSE20DB_TH_HI);
+ alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB,
+ phy_val);
+ }
+ }
+ } else {
+ alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+ &phy_val);
+ alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE,
+ phy_val & ~ALX_AFE_10BT_100M_TH);
+
+ if (adj_th && hw->lnk_patch) {
+ alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB,
+ ALX_MSE16DB_DOWN);
+ alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB, &phy_val);
+ ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH,
+ ALX_MSE20DB_TH_DEF);
+ alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB, phy_val);
+ }
+ }
+}
+
+
+/* NOTE:
+ * 1. phy link must be established before calling this function
+ * 2. wol option (pattern,magic,link,etc.) is configed before call it.
+ */
+int alx_pre_suspend(struct alx_hw *hw, int speed)
+{
+ u32 master, mac, phy, val;
+ int err = 0;
+
+ master = alx_read_mem32(hw, ALX_MASTER);
+ master &= ~ALX_MASTER_PCLKSEL_SRDS;
+ mac = hw->rx_ctrl;
+ /* 10/100 half */
+ ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED, ALX_MAC_CTRL_SPEED_10_100);
+ mac &= ~(ALX_MAC_CTRL_FULLD | ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN);
+
+ phy = alx_read_mem32(hw, ALX_PHY_CTRL);
+ phy &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_CLS);
+ phy |= ALX_PHY_CTRL_RST_ANALOG | ALX_PHY_CTRL_HIB_PULSE |
+ ALX_PHY_CTRL_HIB_EN;
+
+ /* without any activity */
+ if (!(hw->sleep_ctrl & ALX_SLEEP_ACTIVE)) {
+ err = alx_write_phy_reg(hw, ALX_MII_IER, 0);
+ if (err)
+ return err;
+ phy |= ALX_PHY_CTRL_IDDQ | ALX_PHY_CTRL_POWER_DOWN;
+ } else {
+ if (hw->sleep_ctrl & (ALX_SLEEP_WOL_MAGIC | ALX_SLEEP_CIFS))
+ mac |= ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_BRD_EN;
+ if (hw->sleep_ctrl & ALX_SLEEP_CIFS)
+ mac |= ALX_MAC_CTRL_TX_EN;
+ if (speed % 10 == DUPLEX_FULL)
+ mac |= ALX_MAC_CTRL_FULLD;
+ if (speed >= SPEED_1000)
+ ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED,
+ ALX_MAC_CTRL_SPEED_1000);
+ phy |= ALX_PHY_CTRL_DSPRST_OUT;
+ err = alx_write_phy_ext(hw, ALX_MIIEXT_ANEG,
+ ALX_MIIEXT_S3DIG10,
+ ALX_MIIEXT_S3DIG10_SL);
+ if (err)
+ return err;
+ }
+
+ alx_enable_osc(hw);
+ hw->rx_ctrl = mac;
+ alx_write_mem32(hw, ALX_MASTER, master);
+ alx_write_mem32(hw, ALX_MAC_CTRL, mac);
+ alx_write_mem32(hw, ALX_PHY_CTRL, phy);
+
+ /* set val of PDLL D3PLLOFF */
+ val = alx_read_mem32(hw, ALX_PDLL_TRNS1);
+ val |= ALX_PDLL_TRNS1_D3PLLOFF_EN;
+ alx_write_mem32(hw, ALX_PDLL_TRNS1, val);
+
+ return 0;
+}
+
+bool alx_phy_configured(struct alx_hw *hw)
+{
+ u32 cfg, hw_cfg;
+
+ cfg = ethadv_to_hw_cfg(hw, hw->adv_cfg);
+ cfg = ALX_GET_FIELD(cfg, ALX_DRV_PHY);
+ hw_cfg = alx_get_phy_config(hw);
+
+ if (hw_cfg == ALX_DRV_PHY_UNKNOWN)
+ return false;
+
+ return cfg == hw_cfg;
+}
+
+int alx_get_phy_link(struct alx_hw *hw, int *speed)
+{
+ struct pci_dev *pdev = hw->pdev;
+ u16 bmsr, giga;
+ int err;
+
+ err = alx_read_phy_reg(hw, MII_BMSR, &bmsr);
+ if (err)
+ return err;
+
+ err = alx_read_phy_reg(hw, MII_BMSR, &bmsr);
+ if (err)
+ return err;
+
+ if (!(bmsr & BMSR_LSTATUS)) {
+ *speed = SPEED_UNKNOWN;
+ return 0;
+ }
+
+ /* speed/duplex result is saved in PHY Specific Status Register */
+ err = alx_read_phy_reg(hw, ALX_MII_GIGA_PSSR, &giga);
+ if (err)
+ return err;
+
+ if (!(giga & ALX_GIGA_PSSR_SPD_DPLX_RESOLVED))
+ goto wrong_speed;
+
+ switch (giga & ALX_GIGA_PSSR_SPEED) {
+ case ALX_GIGA_PSSR_1000MBS:
+ *speed = SPEED_1000;
+ break;
+ case ALX_GIGA_PSSR_100MBS:
+ *speed = SPEED_100;
+ break;
+ case ALX_GIGA_PSSR_10MBS:
+ *speed = SPEED_10;
+ break;
+ default:
+ goto wrong_speed;
+ }
+
+ *speed += (giga & ALX_GIGA_PSSR_DPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+ return 1;
+
+wrong_speed:
+ dev_err(&pdev->dev, "invalid PHY speed/duplex: 0x%x\n", giga);
+ return -EINVAL;
+}
+
+int alx_clear_phy_intr(struct alx_hw *hw)
+{
+ u16 isr;
+
+ /* clear interrupt status by reading it */
+ return alx_read_phy_reg(hw, ALX_MII_ISR, &isr);
+}
+
+int alx_config_wol(struct alx_hw *hw)
+{
+ u32 wol = 0;
+ int err = 0;
+
+ /* turn on magic packet event */
+ if (hw->sleep_ctrl & ALX_SLEEP_WOL_MAGIC)
+ wol |= ALX_WOL0_MAGIC_EN | ALX_WOL0_PME_MAGIC_EN;
+
+ /* turn on link up event */
+ if (hw->sleep_ctrl & ALX_SLEEP_WOL_PHY) {
+ wol |= ALX_WOL0_LINK_EN | ALX_WOL0_PME_LINK;
+ /* only link up can wake up */
+ err = alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP);
+ }
+ alx_write_mem32(hw, ALX_WOL0, wol);
+
+ return err;
+}
+
+void alx_disable_rss(struct alx_hw *hw)
+{
+ u32 ctrl = alx_read_mem32(hw, ALX_RXQ0);
+
+ ctrl &= ~ALX_RXQ0_RSS_HASH_EN;
+ alx_write_mem32(hw, ALX_RXQ0, ctrl);
+}
+
+void alx_configure_basic(struct alx_hw *hw)
+{
+ u32 val, raw_mtu, max_payload;
+ u16 val16;
+ u8 chip_rev = alx_hw_revision(hw);
+
+ alx_set_macaddr(hw, hw->mac_addr);
+
+ alx_write_mem32(hw, ALX_CLK_GATE, ALX_CLK_GATE_ALL);
+
+ /* idle timeout to switch clk_125M */
+ if (chip_rev >= ALX_REV_B0)
+ alx_write_mem32(hw, ALX_IDLE_DECISN_TIMER,
+ ALX_IDLE_DECISN_TIMER_DEF);
+
+ alx_write_mem32(hw, ALX_SMB_TIMER, hw->smb_timer * 500UL);
+
+ val = alx_read_mem32(hw, ALX_MASTER);
+ val |= ALX_MASTER_IRQMOD2_EN |
+ ALX_MASTER_IRQMOD1_EN |
+ ALX_MASTER_SYSALVTIMER_EN;
+ alx_write_mem32(hw, ALX_MASTER, val);
+ alx_write_mem32(hw, ALX_IRQ_MODU_TIMER,
+ (hw->imt >> 1) << ALX_IRQ_MODU_TIMER1_SHIFT);
+ /* intr re-trig timeout */
+ alx_write_mem32(hw, ALX_INT_RETRIG, ALX_INT_RETRIG_TO);
+ /* tpd threshold to trig int */
+ alx_write_mem32(hw, ALX_TINT_TPD_THRSHLD, hw->ith_tpd);
+ alx_write_mem32(hw, ALX_TINT_TIMER, hw->imt);
+
+ raw_mtu = hw->mtu + ETH_HLEN;
+ alx_write_mem32(hw, ALX_MTU, raw_mtu + 8);
+ if (raw_mtu > ALX_MTU_JUMBO_TH)
+ hw->rx_ctrl &= ~ALX_MAC_CTRL_FAST_PAUSE;
+
+ if ((raw_mtu + 8) < ALX_TXQ1_JUMBO_TSO_TH)
+ val = (raw_mtu + 8 + 7) >> 3;
+ else
+ val = ALX_TXQ1_JUMBO_TSO_TH >> 3;
+ alx_write_mem32(hw, ALX_TXQ1, val | ALX_TXQ1_ERRLGPKT_DROP_EN);
+
+ max_payload = pcie_get_readrq(hw->pdev) >> 8;
+ /*
+ * if BIOS had changed the default dma read max length,
+ * restore it to default value
+ */
+ if (max_payload < ALX_DEV_CTRL_MAXRRS_MIN)
+ pcie_set_readrq(hw->pdev, 128 << ALX_DEV_CTRL_MAXRRS_MIN);
+
+ val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_TXQ0_TPD_BURSTPREF_SHIFT |
+ ALX_TXQ0_MODE_ENHANCE | ALX_TXQ0_LSO_8023_EN |
+ ALX_TXQ0_SUPT_IPOPT |
+ ALX_TXQ_TXF_BURST_PREF_DEF << ALX_TXQ0_TXF_BURST_PREF_SHIFT;
+ alx_write_mem32(hw, ALX_TXQ0, val);
+ val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q1_NUMPREF_SHIFT |
+ ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q2_NUMPREF_SHIFT |
+ ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q3_NUMPREF_SHIFT |
+ ALX_HQTPD_BURST_EN;
+ alx_write_mem32(hw, ALX_HQTPD, val);
+
+ /* rxq, flow control */
+ val = alx_read_mem32(hw, ALX_SRAM5);
+ val = ALX_GET_FIELD(val, ALX_SRAM_RXF_LEN) << 3;
+ if (val > ALX_SRAM_RXF_LEN_8K) {
+ val16 = ALX_MTU_STD_ALGN >> 3;
+ val = (val - ALX_RXQ2_RXF_FLOW_CTRL_RSVD) >> 3;
+ } else {
+ val16 = ALX_MTU_STD_ALGN >> 3;
+ val = (val - ALX_MTU_STD_ALGN) >> 3;
+ }
+ alx_write_mem32(hw, ALX_RXQ2,
+ val16 << ALX_RXQ2_RXF_XOFF_THRESH_SHIFT |
+ val << ALX_RXQ2_RXF_XON_THRESH_SHIFT);
+ val = ALX_RXQ0_NUM_RFD_PREF_DEF << ALX_RXQ0_NUM_RFD_PREF_SHIFT |
+ ALX_RXQ0_RSS_MODE_DIS << ALX_RXQ0_RSS_MODE_SHIFT |
+ ALX_RXQ0_IDT_TBL_SIZE_DEF << ALX_RXQ0_IDT_TBL_SIZE_SHIFT |
+ ALX_RXQ0_RSS_HSTYP_ALL | ALX_RXQ0_RSS_HASH_EN |
+ ALX_RXQ0_IPV6_PARSE_EN;
+
+ if (alx_hw_giga(hw))
+ ALX_SET_FIELD(val, ALX_RXQ0_ASPM_THRESH,
+ ALX_RXQ0_ASPM_THRESH_100M);
+
+ alx_write_mem32(hw, ALX_RXQ0, val);
+
+ val = alx_read_mem32(hw, ALX_DMA);
+ val = ALX_DMA_RORDER_MODE_OUT << ALX_DMA_RORDER_MODE_SHIFT |
+ ALX_DMA_RREQ_PRI_DATA |
+ max_payload << ALX_DMA_RREQ_BLEN_SHIFT |
+ ALX_DMA_WDLY_CNT_DEF << ALX_DMA_WDLY_CNT_SHIFT |
+ ALX_DMA_RDLY_CNT_DEF << ALX_DMA_RDLY_CNT_SHIFT |
+ (hw->dma_chnl - 1) << ALX_DMA_RCHNL_SEL_SHIFT;
+ alx_write_mem32(hw, ALX_DMA, val);
+
+ /* default multi-tx-q weights */
+ val = ALX_WRR_PRI_RESTRICT_NONE << ALX_WRR_PRI_SHIFT |
+ 4 << ALX_WRR_PRI0_SHIFT |
+ 4 << ALX_WRR_PRI1_SHIFT |
+ 4 << ALX_WRR_PRI2_SHIFT |
+ 4 << ALX_WRR_PRI3_SHIFT;
+ alx_write_mem32(hw, ALX_WRR, val);
+}
+
+static inline u32 alx_speed_to_ethadv(int speed)
+{
+ switch (speed) {
+ case SPEED_1000 + DUPLEX_FULL:
+ return ADVERTISED_1000baseT_Full;
+ case SPEED_100 + DUPLEX_FULL:
+ return ADVERTISED_100baseT_Full;
+ case SPEED_100 + DUPLEX_HALF:
+ return ADVERTISED_10baseT_Half;
+ case SPEED_10 + DUPLEX_FULL:
+ return ADVERTISED_10baseT_Full;
+ case SPEED_10 + DUPLEX_HALF:
+ return ADVERTISED_10baseT_Half;
+ default:
+ return 0;
+ }
+}
+
+int alx_select_powersaving_speed(struct alx_hw *hw, int *speed)
+{
+ int i, err, spd;
+ u16 lpa;
+
+ err = alx_get_phy_link(hw, &spd);
+ if (err < 0)
+ return err;
+
+ if (spd == SPEED_UNKNOWN)
+ return 0;
+
+ err = alx_read_phy_reg(hw, MII_LPA, &lpa);
+ if (err)
+ return err;
+
+ if (!(lpa & LPA_LPACK)) {
+ *speed = spd;
+ return 0;
+ }
+
+ if (lpa & LPA_10FULL)
+ *speed = SPEED_10 + DUPLEX_FULL;
+ else if (lpa & LPA_10HALF)
+ *speed = SPEED_10 + DUPLEX_HALF;
+ else if (lpa & LPA_100FULL)
+ *speed = SPEED_100 + DUPLEX_FULL;
+ else
+ *speed = SPEED_100 + DUPLEX_HALF;
+
+ if (*speed != spd) {
+ err = alx_write_phy_reg(hw, ALX_MII_IER, 0);
+ if (err)
+ return err;
+ err = alx_setup_speed_duplex(hw,
+ alx_speed_to_ethadv(*speed) |
+ ADVERTISED_Autoneg,
+ ALX_FC_ANEG | ALX_FC_RX |
+ ALX_FC_TX);
+ if (err)
+ return err;
+
+ /* wait for linkup */
+ for (i = 0; i < ALX_MAX_SETUP_LNK_CYCLE; i++) {
+ int speed2;
+
+ msleep(100);
+
+ err = alx_get_phy_link(hw, &speed2);
+ if (err < 0)
+ return err;
+ if (speed2 != SPEED_UNKNOWN)
+ break;
+ }
+ if (i == ALX_MAX_SETUP_LNK_CYCLE)
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+bool alx_get_phy_info(struct alx_hw *hw)
+{
+ u16 devs1, devs2;
+
+ if (alx_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id[0]) ||
+ alx_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id[1]))
+ return false;
+
+ /* since we haven't PMA/PMD status2 register, we can't
+ * use mdio45_probe function for prtad and mmds.
+ * use fixed MMD3 to get mmds.
+ */
+ if (alx_read_phy_ext(hw, 3, MDIO_DEVS1, &devs1) ||
+ alx_read_phy_ext(hw, 3, MDIO_DEVS2, &devs2))
+ return false;
+ hw->mdio.mmds = devs1 | devs2 << 16;
+
+ return true;
+}
diff --git a/drivers/net/ethernet/atheros/alx/hw.h b/drivers/net/ethernet/atheros/alx/hw.h
new file mode 100644
index 0000000..65e723d
--- /dev/null
+++ b/drivers/net/ethernet/atheros/alx/hw.h
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ALX_HW_H_
+#define ALX_HW_H_
+#include <linux/types.h>
+#include <linux/mdio.h>
+#include <linux/pci.h>
+#include "reg.h"
+
+/* Transmit Packet Descriptor, contains 4 32-bit words.
+ *
+ * 31 16 0
+ * +----------------+----------------+
+ * | vlan-tag | buf length |
+ * +----------------+----------------+
+ * | Word 1 |
+ * +----------------+----------------+
+ * | Word 2: buf addr lo |
+ * +----------------+----------------+
+ * | Word 3: buf addr hi |
+ * +----------------+----------------+
+ *
+ * Word 2 and 3 combine to form a 64-bit buffer address
+ *
+ * Word 1 has three forms, depending on the state of bit 8/12/13:
+ * if bit8 =='1', the definition is just for custom checksum offload.
+ * if bit8 == '0' && bit12 == '1' && bit13 == '1', the *FIRST* descriptor
+ * for the skb is special for LSO V2, Word 2 become total skb length ,
+ * Word 3 is meaningless.
+ * other condition, the definition is for general skb or ip/tcp/udp
+ * checksum or LSO(TSO) offload.
+ *
+ * Here is the depiction:
+ *
+ * 0-+ 0-+
+ * 1 | 1 |
+ * 2 | 2 |
+ * 3 | Payload offset 3 | L4 header offset
+ * 4 | (7:0) 4 | (7:0)
+ * 5 | 5 |
+ * 6 | 6 |
+ * 7-+ 7-+
+ * 8 Custom csum enable = 1 8 Custom csum enable = 0
+ * 9 General IPv4 checksum 9 General IPv4 checksum
+ * 10 General TCP checksum 10 General TCP checksum
+ * 11 General UDP checksum 11 General UDP checksum
+ * 12 Large Send Segment enable 12 Large Send Segment enable
+ * 13 Large Send Segment type 13 Large Send Segment type
+ * 14 VLAN tagged 14 VLAN tagged
+ * 15 Insert VLAN tag 15 Insert VLAN tag
+ * 16 IPv4 packet 16 IPv4 packet
+ * 17 Ethernet frame type 17 Ethernet frame type
+ * 18-+ 18-+
+ * 19 | 19 |
+ * 20 | 20 |
+ * 21 | Custom csum offset 21 |
+ * 22 | (25:18) 22 |
+ * 23 | 23 | MSS (30:18)
+ * 24 | 24 |
+ * 25-+ 25 |
+ * 26-+ 26 |
+ * 27 | 27 |
+ * 28 | Reserved 28 |
+ * 29 | 29 |
+ * 30-+ 30-+
+ * 31 End of packet 31 End of packet
+ */
+struct alx_txd {
+ __le16 len;
+ __le16 vlan_tag;
+ __le32 word1;
+ union {
+ __le64 addr;
+ struct {
+ __le32 pkt_len;
+ __le32 resvd;
+ } l;
+ } adrl;
+} __packed;
+
+/* tpd word 1 */
+#define TPD_CXSUMSTART_MASK 0x00FF
+#define TPD_CXSUMSTART_SHIFT 0
+#define TPD_L4HDROFFSET_MASK 0x00FF
+#define TPD_L4HDROFFSET_SHIFT 0
+#define TPD_CXSUM_EN_MASK 0x0001
+#define TPD_CXSUM_EN_SHIFT 8
+#define TPD_IP_XSUM_MASK 0x0001
+#define TPD_IP_XSUM_SHIFT 9
+#define TPD_TCP_XSUM_MASK 0x0001
+#define TPD_TCP_XSUM_SHIFT 10
+#define TPD_UDP_XSUM_MASK 0x0001
+#define TPD_UDP_XSUM_SHIFT 11
+#define TPD_LSO_EN_MASK 0x0001
+#define TPD_LSO_EN_SHIFT 12
+#define TPD_LSO_V2_MASK 0x0001
+#define TPD_LSO_V2_SHIFT 13
+#define TPD_VLTAGGED_MASK 0x0001
+#define TPD_VLTAGGED_SHIFT 14
+#define TPD_INS_VLTAG_MASK 0x0001
+#define TPD_INS_VLTAG_SHIFT 15
+#define TPD_IPV4_MASK 0x0001
+#define TPD_IPV4_SHIFT 16
+#define TPD_ETHTYPE_MASK 0x0001
+#define TPD_ETHTYPE_SHIFT 17
+#define TPD_CXSUMOFFSET_MASK 0x00FF
+#define TPD_CXSUMOFFSET_SHIFT 18
+#define TPD_MSS_MASK 0x1FFF
+#define TPD_MSS_SHIFT 18
+#define TPD_EOP_MASK 0x0001
+#define TPD_EOP_SHIFT 31
+
+#define DESC_GET(_x, _name) ((_x) >> _name##SHIFT & _name##MASK)
+
+/* Receive Free Descriptor */
+struct alx_rfd {
+ __le64 addr; /* data buffer address, length is
+ * declared in register --- every
+ * buffer has the same size
+ */
+} __packed;
+
+/* Receive Return Descriptor, contains 4 32-bit words.
+ *
+ * 31 16 0
+ * +----------------+----------------+
+ * | Word 0 |
+ * +----------------+----------------+
+ * | Word 1: RSS Hash value |
+ * +----------------+----------------+
+ * | Word 2 |
+ * +----------------+----------------+
+ * | Word 3 |
+ * +----------------+----------------+
+ *
+ * Word 0 depiction & Word 2 depiction:
+ *
+ * 0--+ 0--+
+ * 1 | 1 |
+ * 2 | 2 |
+ * 3 | 3 |
+ * 4 | 4 |
+ * 5 | 5 |
+ * 6 | 6 |
+ * 7 | IP payload checksum 7 | VLAN tag
+ * 8 | (15:0) 8 | (15:0)
+ * 9 | 9 |
+ * 10 | 10 |
+ * 11 | 11 |
+ * 12 | 12 |
+ * 13 | 13 |
+ * 14 | 14 |
+ * 15-+ 15-+
+ * 16-+ 16-+
+ * 17 | Number of RFDs 17 |
+ * 18 | (19:16) 18 |
+ * 19-+ 19 | Protocol ID
+ * 20-+ 20 | (23:16)
+ * 21 | 21 |
+ * 22 | 22 |
+ * 23 | 23-+
+ * 24 | 24 | Reserved
+ * 25 | Start index of RFD-ring 25-+
+ * 26 | (31:20) 26 | RSS Q-num (27:25)
+ * 27 | 27-+
+ * 28 | 28-+
+ * 29 | 29 | RSS Hash algorithm
+ * 30 | 30 | (31:28)
+ * 31-+ 31-+
+ *
+ * Word 3 depiction:
+ *
+ * 0--+
+ * 1 |
+ * 2 |
+ * 3 |
+ * 4 |
+ * 5 |
+ * 6 |
+ * 7 | Packet length (include FCS)
+ * 8 | (13:0)
+ * 9 |
+ * 10 |
+ * 11 |
+ * 12 |
+ * 13-+
+ * 14 L4 Header checksum error
+ * 15 IPv4 checksum error
+ * 16 VLAN tagged
+ * 17-+
+ * 18 | Protocol ID (19:17)
+ * 19-+
+ * 20 Receive error summary
+ * 21 FCS(CRC) error
+ * 22 Frame alignment error
+ * 23 Truncated packet
+ * 24 Runt packet
+ * 25 Incomplete packet due to insufficient rx-desc
+ * 26 Broadcast packet
+ * 27 Multicast packet
+ * 28 Ethernet type (EII or 802.3)
+ * 29 FIFO overflow
+ * 30 Length error (for 802.3, length field mismatch with actual len)
+ * 31 Updated, indicate to driver that this RRD is refreshed.
+ */
+struct alx_rrd {
+ __le32 word0;
+ __le32 rss_hash;
+ __le32 word2;
+ __le32 word3;
+} __packed;
+
+/* rrd word 0 */
+#define RRD_XSUM_MASK 0xFFFF
+#define RRD_XSUM_SHIFT 0
+#define RRD_NOR_MASK 0x000F
+#define RRD_NOR_SHIFT 16
+#define RRD_SI_MASK 0x0FFF
+#define RRD_SI_SHIFT 20
+
+/* rrd word 2 */
+#define RRD_VLTAG_MASK 0xFFFF
+#define RRD_VLTAG_SHIFT 0
+#define RRD_PID_MASK 0x00FF
+#define RRD_PID_SHIFT 16
+/* non-ip packet */
+#define RRD_PID_NONIP 0
+/* ipv4(only) */
+#define RRD_PID_IPV4 1
+/* tcp/ipv6 */
+#define RRD_PID_IPV6TCP 2
+/* tcp/ipv4 */
+#define RRD_PID_IPV4TCP 3
+/* udp/ipv6 */
+#define RRD_PID_IPV6UDP 4
+/* udp/ipv4 */
+#define RRD_PID_IPV4UDP 5
+/* ipv6(only) */
+#define RRD_PID_IPV6 6
+/* LLDP packet */
+#define RRD_PID_LLDP 7
+/* 1588 packet */
+#define RRD_PID_1588 8
+#define RRD_RSSQ_MASK 0x0007
+#define RRD_RSSQ_SHIFT 25
+#define RRD_RSSALG_MASK 0x000F
+#define RRD_RSSALG_SHIFT 28
+#define RRD_RSSALG_TCPV6 0x1
+#define RRD_RSSALG_IPV6 0x2
+#define RRD_RSSALG_TCPV4 0x4
+#define RRD_RSSALG_IPV4 0x8
+
+/* rrd word 3 */
+#define RRD_PKTLEN_MASK 0x3FFF
+#define RRD_PKTLEN_SHIFT 0
+#define RRD_ERR_L4_MASK 0x0001
+#define RRD_ERR_L4_SHIFT 14
+#define RRD_ERR_IPV4_MASK 0x0001
+#define RRD_ERR_IPV4_SHIFT 15
+#define RRD_VLTAGGED_MASK 0x0001
+#define RRD_VLTAGGED_SHIFT 16
+#define RRD_OLD_PID_MASK 0x0007
+#define RRD_OLD_PID_SHIFT 17
+#define RRD_ERR_RES_MASK 0x0001
+#define RRD_ERR_RES_SHIFT 20
+#define RRD_ERR_FCS_MASK 0x0001
+#define RRD_ERR_FCS_SHIFT 21
+#define RRD_ERR_FAE_MASK 0x0001
+#define RRD_ERR_FAE_SHIFT 22
+#define RRD_ERR_TRUNC_MASK 0x0001
+#define RRD_ERR_TRUNC_SHIFT 23
+#define RRD_ERR_RUNT_MASK 0x0001
+#define RRD_ERR_RUNT_SHIFT 24
+#define RRD_ERR_ICMP_MASK 0x0001
+#define RRD_ERR_ICMP_SHIFT 25
+#define RRD_BCAST_MASK 0x0001
+#define RRD_BCAST_SHIFT 26
+#define RRD_MCAST_MASK 0x0001
+#define RRD_MCAST_SHIFT 27
+#define RRD_ETHTYPE_MASK 0x0001
+#define RRD_ETHTYPE_SHIFT 28
+#define RRD_ERR_FIFOV_MASK 0x0001
+#define RRD_ERR_FIFOV_SHIFT 29
+#define RRD_ERR_LEN_MASK 0x0001
+#define RRD_ERR_LEN_SHIFT 30
+#define RRD_UPDATED_MASK 0x0001
+#define RRD_UPDATED_SHIFT 31
+
+
+#define ALX_MAX_SETUP_LNK_CYCLE 50
+
+/* for FlowControl */
+#define ALX_FC_RX 0x01
+#define ALX_FC_TX 0x02
+#define ALX_FC_ANEG 0x04
+
+/* for sleep control */
+#define ALX_SLEEP_WOL_PHY 0x00000001
+#define ALX_SLEEP_WOL_MAGIC 0x00000002
+#define ALX_SLEEP_CIFS 0x00000004
+#define ALX_SLEEP_ACTIVE (ALX_SLEEP_WOL_PHY | \
+ ALX_SLEEP_WOL_MAGIC | \
+ ALX_SLEEP_CIFS)
+
+/* for RSS hash type */
+#define ALX_RSS_HASH_TYPE_IPV4 0x1
+#define ALX_RSS_HASH_TYPE_IPV4_TCP 0x2
+#define ALX_RSS_HASH_TYPE_IPV6 0x4
+#define ALX_RSS_HASH_TYPE_IPV6_TCP 0x8
+#define ALX_RSS_HASH_TYPE_ALL (ALX_RSS_HASH_TYPE_IPV4 | \
+ ALX_RSS_HASH_TYPE_IPV4_TCP | \
+ ALX_RSS_HASH_TYPE_IPV6 | \
+ ALX_RSS_HASH_TYPE_IPV6_TCP)
+#define ALX_DEF_RXBUF_SIZE 1536
+#define ALX_MAX_JUMBO_PKT_SIZE (9*1024)
+#define ALX_MAX_TSO_PKT_SIZE (7*1024)
+#define ALX_MAX_FRAME_SIZE ALX_MAX_JUMBO_PKT_SIZE
+#define ALX_MIN_FRAME_SIZE 68
+#define ALX_RAW_MTU(_mtu) (_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN)
+
+#define ALX_MAX_RX_QUEUES 8
+#define ALX_MAX_TX_QUEUES 4
+#define ALX_MAX_HANDLED_INTRS 5
+
+#define ALX_ISR_MISC (ALX_ISR_PCIE_LNKDOWN | \
+ ALX_ISR_DMAW | \
+ ALX_ISR_DMAR | \
+ ALX_ISR_SMB | \
+ ALX_ISR_MANU | \
+ ALX_ISR_TIMER)
+
+#define ALX_ISR_FATAL (ALX_ISR_PCIE_LNKDOWN | \
+ ALX_ISR_DMAW | ALX_ISR_DMAR)
+
+#define ALX_ISR_ALERT (ALX_ISR_RXF_OV | \
+ ALX_ISR_TXF_UR | \
+ ALX_ISR_RFD_UR)
+
+#define ALX_ISR_ALL_QUEUES (ALX_ISR_TX_Q0 | \
+ ALX_ISR_TX_Q1 | \
+ ALX_ISR_TX_Q2 | \
+ ALX_ISR_TX_Q3 | \
+ ALX_ISR_RX_Q0 | \
+ ALX_ISR_RX_Q1 | \
+ ALX_ISR_RX_Q2 | \
+ ALX_ISR_RX_Q3 | \
+ ALX_ISR_RX_Q4 | \
+ ALX_ISR_RX_Q5 | \
+ ALX_ISR_RX_Q6 | \
+ ALX_ISR_RX_Q7)
+
+/* maximum interrupt vectors for msix */
+#define ALX_MAX_MSIX_INTRS 16
+
+#define ALX_GET_FIELD(_data, _field) \
+ (((_data) >> _field ## _SHIFT) & _field ## _MASK)
+
+#define ALX_SET_FIELD(_data, _field, _value) do { \
+ (_data) &= ~(_field ## _MASK << _field ## _SHIFT); \
+ (_data) |= ((_value) & _field ## _MASK) << _field ## _SHIFT;\
+ } while (0)
+
+struct alx_hw {
+ struct pci_dev *pdev;
+ u8 __iomem *hw_addr;
+
+ /* current & permanent mac addr */
+ u8 mac_addr[ETH_ALEN];
+ u8 perm_addr[ETH_ALEN];
+
+ u16 mtu;
+ u16 imt;
+ u8 dma_chnl;
+ u8 max_dma_chnl;
+ /* tpd threshold to trig INT */
+ u32 ith_tpd;
+ u32 rx_ctrl;
+ u32 mc_hash[2];
+
+ u32 smb_timer;
+ /* SPEED_* + DUPLEX_*, SPEED_UNKNOWN if link is down */
+ int link_speed;
+
+ /* auto-neg advertisement or force mode config */
+ u32 adv_cfg;
+ u8 flowctrl;
+
+ u32 sleep_ctrl;
+
+ spinlock_t mdio_lock;
+ struct mdio_if_info mdio;
+ u16 phy_id[2];
+
+ /* PHY link patch flag */
+ bool lnk_patch;
+};
+
+static inline int alx_hw_revision(struct alx_hw *hw)
+{
+ return hw->pdev->revision >> ALX_PCI_REVID_SHIFT;
+}
+
+static inline bool alx_hw_with_cr(struct alx_hw *hw)
+{
+ return hw->pdev->revision & 1;
+}
+
+static inline bool alx_hw_giga(struct alx_hw *hw)
+{
+ return hw->pdev->device & 1;
+}
+
+static inline void alx_write_mem8(struct alx_hw *hw, u32 reg, u8 val)
+{
+ writeb(val, hw->hw_addr + reg);
+}
+
+static inline void alx_write_mem16(struct alx_hw *hw, u32 reg, u16 val)
+{
+ writew(val, hw->hw_addr + reg);
+}
+
+static inline u16 alx_read_mem16(struct alx_hw *hw, u32 reg)
+{
+ return readw(hw->hw_addr + reg);
+}
+
+static inline void alx_write_mem32(struct alx_hw *hw, u32 reg, u32 val)
+{
+ writel(val, hw->hw_addr + reg);
+}
+
+static inline u32 alx_read_mem32(struct alx_hw *hw, u32 reg)
+{
+ return readl(hw->hw_addr + reg);
+}
+
+static inline void alx_post_write(struct alx_hw *hw)
+{
+ readl(hw->hw_addr);
+}
+
+int alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr);
+void alx_reset_phy(struct alx_hw *hw);
+void alx_reset_pcie(struct alx_hw *hw);
+void alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en);
+int alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl);
+void alx_post_phy_link(struct alx_hw *hw);
+int alx_pre_suspend(struct alx_hw *hw, int speed);
+int alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data);
+int alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data);
+int alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata);
+int alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data);
+int alx_get_phy_link(struct alx_hw *hw, int *speed);
+int alx_clear_phy_intr(struct alx_hw *hw);
+int alx_config_wol(struct alx_hw *hw);
+void alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc);
+void alx_start_mac(struct alx_hw *hw);
+int alx_reset_mac(struct alx_hw *hw);
+void alx_set_macaddr(struct alx_hw *hw, const u8 *addr);
+bool alx_phy_configured(struct alx_hw *hw);
+void alx_configure_basic(struct alx_hw *hw);
+void alx_disable_rss(struct alx_hw *hw);
+int alx_select_powersaving_speed(struct alx_hw *hw, int *speed);
+bool alx_get_phy_info(struct alx_hw *hw);
+
+#endif
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
new file mode 100644
index 0000000..418de8b
--- /dev/null
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -0,0 +1,1625 @@
+/*
+ * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/if_vlan.h>
+#include <linux/mdio.h>
+#include <linux/aer.h>
+#include <linux/bitops.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/ip6_checksum.h>
+#include <linux/crc32.h>
+#include "alx.h"
+#include "hw.h"
+#include "reg.h"
+
+const char alx_drv_name[] = "alx";
+
+
+static void alx_free_txbuf(struct alx_priv *alx, int entry)
+{
+ struct alx_buffer *txb = &alx->txq.bufs[entry];
+
+ if (dma_unmap_len(txb, size)) {
+ dma_unmap_single(&alx->hw.pdev->dev,
+ dma_unmap_addr(txb, dma),
+ dma_unmap_len(txb, size),
+ DMA_TO_DEVICE);
+ dma_unmap_len_set(txb, size, 0);
+ }
+
+ if (txb->skb) {
+ dev_kfree_skb_any(txb->skb);
+ txb->skb = NULL;
+ }
+}
+
+static int alx_refill_rx_ring(struct alx_priv *alx, gfp_t gfp)
+{
+ struct alx_rx_queue *rxq = &alx->rxq;
+ struct sk_buff *skb;
+ struct alx_buffer *cur_buf;
+ dma_addr_t dma;
+ u16 cur, next, count = 0;
+
+ next = cur = rxq->write_idx;
+ if (++next == alx->rx_ringsz)
+ next = 0;
+ cur_buf = &rxq->bufs[cur];
+
+ while (!cur_buf->skb && next != rxq->read_idx) {
+ struct alx_rfd *rfd = &rxq->rfd[cur];
+
+ skb = __netdev_alloc_skb(alx->dev, alx->rxbuf_size, gfp);
+ if (!skb)
+ break;
+ dma = dma_map_single(&alx->hw.pdev->dev,
+ skb->data, alx->rxbuf_size,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&alx->hw.pdev->dev, dma)) {
+ dev_kfree_skb(skb);
+ break;
+ }
+
+ /* Unfortunately, RX descriptor buffers must be 4-byte
+ * aligned, so we can't use IP alignment.
+ */
+ if (WARN_ON(dma & 3)) {
+ dev_kfree_skb(skb);
+ break;
+ }
+
+ cur_buf->skb = skb;
+ dma_unmap_len_set(cur_buf, size, alx->rxbuf_size);
+ dma_unmap_addr_set(cur_buf, dma, dma);
+ rfd->addr = cpu_to_le64(dma);
+
+ cur = next;
+ if (++next == alx->rx_ringsz)
+ next = 0;
+ cur_buf = &rxq->bufs[cur];
+ count++;
+ }
+
+ if (count) {
+ /* flush all updates before updating hardware */
+ wmb();
+ rxq->write_idx = cur;
+ alx_write_mem16(&alx->hw, ALX_RFD_PIDX, cur);
+ }
+
+ return count;
+}
+
+static inline int alx_tpd_avail(struct alx_priv *alx)
+{
+ struct alx_tx_queue *txq = &alx->txq;
+
+ if (txq->write_idx >= txq->read_idx)
+ return alx->tx_ringsz + txq->read_idx - txq->write_idx - 1;
+ return txq->read_idx - txq->write_idx - 1;
+}
+
+static bool alx_clean_tx_irq(struct alx_priv *alx)
+{
+ struct alx_tx_queue *txq = &alx->txq;
+ u16 hw_read_idx, sw_read_idx;
+ unsigned int total_bytes = 0, total_packets = 0;
+ int budget = ALX_DEFAULT_TX_WORK;
+
+ sw_read_idx = txq->read_idx;
+ hw_read_idx = alx_read_mem16(&alx->hw, ALX_TPD_PRI0_CIDX);
+
+ if (sw_read_idx != hw_read_idx) {
+ while (sw_read_idx != hw_read_idx && budget > 0) {
+ struct sk_buff *skb;
+
+ skb = txq->bufs[sw_read_idx].skb;
+ if (skb) {
+ total_bytes += skb->len;
+ total_packets++;
+ budget--;
+ }
+
+ alx_free_txbuf(alx, sw_read_idx);
+
+ if (++sw_read_idx == alx->tx_ringsz)
+ sw_read_idx = 0;
+ }
+ txq->read_idx = sw_read_idx;
+
+ netdev_completed_queue(alx->dev, total_packets, total_bytes);
+ }
+
+ if (netif_queue_stopped(alx->dev) && netif_carrier_ok(alx->dev) &&
+ alx_tpd_avail(alx) > alx->tx_ringsz/4)
+ netif_wake_queue(alx->dev);
+
+ return sw_read_idx == hw_read_idx;
+}
+
+static void alx_schedule_link_check(struct alx_priv *alx)
+{
+ schedule_work(&alx->link_check_wk);
+}
+
+static void alx_schedule_reset(struct alx_priv *alx)
+{
+ schedule_work(&alx->reset_wk);
+}
+
+static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
+{
+ struct alx_rx_queue *rxq = &alx->rxq;
+ struct alx_rrd *rrd;
+ struct alx_buffer *rxb;
+ struct sk_buff *skb;
+ u16 length, rfd_cleaned = 0;
+
+ while (budget > 0) {
+ rrd = &rxq->rrd[rxq->rrd_read_idx];
+ if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT)))
+ break;
+ rrd->word3 &= ~cpu_to_le32(1 << RRD_UPDATED_SHIFT);
+
+ if (ALX_GET_FIELD(le32_to_cpu(rrd->word0),
+ RRD_SI) != rxq->read_idx ||
+ ALX_GET_FIELD(le32_to_cpu(rrd->word0),
+ RRD_NOR) != 1) {
+ alx_schedule_reset(alx);
+ return 0;
+ }
+
+ rxb = &rxq->bufs[rxq->read_idx];
+ dma_unmap_single(&alx->hw.pdev->dev,
+ dma_unmap_addr(rxb, dma),
+ dma_unmap_len(rxb, size),
+ DMA_FROM_DEVICE);
+ dma_unmap_len_set(rxb, size, 0);
+ skb = rxb->skb;
+ rxb->skb = NULL;
+
+ if (rrd->word3 & cpu_to_le32(1 << RRD_ERR_RES_SHIFT) ||
+ rrd->word3 & cpu_to_le32(1 << RRD_ERR_LEN_SHIFT)) {
+ rrd->word3 = 0;
+ dev_kfree_skb_any(skb);
+ goto next_pkt;
+ }
+
+ length = ALX_GET_FIELD(le32_to_cpu(rrd->word3),
+ RRD_PKTLEN) - ETH_FCS_LEN;
+ skb_put(skb, length);
+ skb->protocol = eth_type_trans(skb, alx->dev);
+
+ skb_checksum_none_assert(skb);
+ if (alx->dev->features & NETIF_F_RXCSUM &&
+ !(rrd->word3 & (cpu_to_le32(1 << RRD_ERR_L4_SHIFT) |
+ cpu_to_le32(1 << RRD_ERR_IPV4_SHIFT)))) {
+ switch (ALX_GET_FIELD(le32_to_cpu(rrd->word2),
+ RRD_PID)) {
+ case RRD_PID_IPV6UDP:
+ case RRD_PID_IPV4UDP:
+ case RRD_PID_IPV4TCP:
+ case RRD_PID_IPV6TCP:
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ break;
+ }
+ }
+
+ napi_gro_receive(&alx->napi, skb);
+ budget--;
+
+next_pkt:
+ if (++rxq->read_idx == alx->rx_ringsz)
+ rxq->read_idx = 0;
+ if (++rxq->rrd_read_idx == alx->rx_ringsz)
+ rxq->rrd_read_idx = 0;
+
+ if (++rfd_cleaned > ALX_RX_ALLOC_THRESH)
+ rfd_cleaned -= alx_refill_rx_ring(alx, GFP_ATOMIC);
+ }
+
+ if (rfd_cleaned)
+ alx_refill_rx_ring(alx, GFP_ATOMIC);
+
+ return budget > 0;
+}
+
+static int alx_poll(struct napi_struct *napi, int budget)
+{
+ struct alx_priv *alx = container_of(napi, struct alx_priv, napi);
+ struct alx_hw *hw = &alx->hw;
+ bool complete = true;
+ unsigned long flags;
+
+ complete = alx_clean_tx_irq(alx) &&
+ alx_clean_rx_irq(alx, budget);
+
+ if (!complete)
+ return 1;
+
+ napi_complete(&alx->napi);
+
+ /* enable interrupt */
+ spin_lock_irqsave(&alx->irq_lock, flags);
+ alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
+ alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+ spin_unlock_irqrestore(&alx->irq_lock, flags);
+
+ alx_post_write(hw);
+
+ return 0;
+}
+
+static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
+{
+ struct alx_hw *hw = &alx->hw;
+ bool write_int_mask = false;
+
+ spin_lock(&alx->irq_lock);
+
+ /* ACK interrupt */
+ alx_write_mem32(hw, ALX_ISR, intr | ALX_ISR_DIS);
+ intr &= alx->int_mask;
+
+ if (intr & ALX_ISR_FATAL) {
+ netif_warn(alx, hw, alx->dev,
+ "fatal interrupt 0x%x, resetting\n", intr);
+ alx_schedule_reset(alx);
+ goto out;
+ }
+
+ if (intr & ALX_ISR_ALERT)
+ netdev_warn(alx->dev, "alert interrupt: 0x%x\n", intr);
+
+ if (intr & ALX_ISR_PHY) {
+ /* suppress PHY interrupt, because the source
+ * is from PHY internal. only the internal status
+ * is cleared, the interrupt status could be cleared.
+ */
+ alx->int_mask &= ~ALX_ISR_PHY;
+ write_int_mask = true;
+ alx_schedule_link_check(alx);
+ }
+
+ if (intr & (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0)) {
+ napi_schedule(&alx->napi);
+ /* mask rx/tx interrupt, enable them when napi complete */
+ alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
+ write_int_mask = true;
+ }
+
+ if (write_int_mask)
+ alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+
+ alx_write_mem32(hw, ALX_ISR, 0);
+
+ out:
+ spin_unlock(&alx->irq_lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t alx_intr_msi(int irq, void *data)
+{
+ struct alx_priv *alx = data;
+
+ return alx_intr_handle(alx, alx_read_mem32(&alx->hw, ALX_ISR));
+}
+
+static irqreturn_t alx_intr_legacy(int irq, void *data)
+{
+ struct alx_priv *alx = data;
+ struct alx_hw *hw = &alx->hw;
+ u32 intr;
+
+ intr = alx_read_mem32(hw, ALX_ISR);
+
+ if (intr & ALX_ISR_DIS || !(intr & alx->int_mask))
+ return IRQ_NONE;
+
+ return alx_intr_handle(alx, intr);
+}
+
+static void alx_init_ring_ptrs(struct alx_priv *alx)
+{
+ struct alx_hw *hw = &alx->hw;
+ u32 addr_hi = ((u64)alx->descmem.dma) >> 32;
+
+ alx->rxq.read_idx = 0;
+ alx->rxq.write_idx = 0;
+ alx->rxq.rrd_read_idx = 0;
+ alx_write_mem32(hw, ALX_RX_BASE_ADDR_HI, addr_hi);
+ alx_write_mem32(hw, ALX_RRD_ADDR_LO, alx->rxq.rrd_dma);
+ alx_write_mem32(hw, ALX_RRD_RING_SZ, alx->rx_ringsz);
+ alx_write_mem32(hw, ALX_RFD_ADDR_LO, alx->rxq.rfd_dma);
+ alx_write_mem32(hw, ALX_RFD_RING_SZ, alx->rx_ringsz);
+ alx_write_mem32(hw, ALX_RFD_BUF_SZ, alx->rxbuf_size);
+
+ alx->txq.read_idx = 0;
+ alx->txq.write_idx = 0;
+ alx_write_mem32(hw, ALX_TX_BASE_ADDR_HI, addr_hi);
+ alx_write_mem32(hw, ALX_TPD_PRI0_ADDR_LO, alx->txq.tpd_dma);
+ alx_write_mem32(hw, ALX_TPD_RING_SZ, alx->tx_ringsz);
+
+ /* load these pointers into the chip */
+ alx_write_mem32(hw, ALX_SRAM9, ALX_SRAM_LOAD_PTR);
+}
+
+static void alx_free_txring_buf(struct alx_priv *alx)
+{
+ struct alx_tx_queue *txq = &alx->txq;
+ int i;
+
+ if (!txq->bufs)
+ return;
+
+ for (i = 0; i < alx->tx_ringsz; i++)
+ alx_free_txbuf(alx, i);
+
+ memset(txq->bufs, 0, alx->tx_ringsz * sizeof(struct alx_buffer));
+ memset(txq->tpd, 0, alx->tx_ringsz * sizeof(struct alx_txd));
+ txq->write_idx = 0;
+ txq->read_idx = 0;
+
+ netdev_reset_queue(alx->dev);
+}
+
+static void alx_free_rxring_buf(struct alx_priv *alx)
+{
+ struct alx_rx_queue *rxq = &alx->rxq;
+ struct alx_buffer *cur_buf;
+ u16 i;
+
+ if (rxq == NULL)
+ return;
+
+ for (i = 0; i < alx->rx_ringsz; i++) {
+ cur_buf = rxq->bufs + i;
+ if (cur_buf->skb) {
+ dma_unmap_single(&alx->hw.pdev->dev,
+ dma_unmap_addr(cur_buf, dma),
+ dma_unmap_len(cur_buf, size),
+ DMA_FROM_DEVICE);
+ dev_kfree_skb(cur_buf->skb);
+ cur_buf->skb = NULL;
+ dma_unmap_len_set(cur_buf, size, 0);
+ dma_unmap_addr_set(cur_buf, dma, 0);
+ }
+ }
+
+ rxq->write_idx = 0;
+ rxq->read_idx = 0;
+ rxq->rrd_read_idx = 0;
+}
+
+static void alx_free_buffers(struct alx_priv *alx)
+{
+ alx_free_txring_buf(alx);
+ alx_free_rxring_buf(alx);
+}
+
+static int alx_reinit_rings(struct alx_priv *alx)
+{
+ alx_free_buffers(alx);
+
+ alx_init_ring_ptrs(alx);
+
+ if (!alx_refill_rx_ring(alx, GFP_KERNEL))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void alx_add_mc_addr(struct alx_hw *hw, const u8 *addr, u32 *mc_hash)
+{
+ u32 crc32, bit, reg;
+
+ crc32 = ether_crc(ETH_ALEN, addr);
+ reg = (crc32 >> 31) & 0x1;
+ bit = (crc32 >> 26) & 0x1F;
+
+ mc_hash[reg] |= BIT(bit);
+}
+
+static void __alx_set_rx_mode(struct net_device *netdev)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+ struct netdev_hw_addr *ha;
+ u32 mc_hash[2] = {};
+
+ if (!(netdev->flags & IFF_ALLMULTI)) {
+ netdev_for_each_mc_addr(ha, netdev)
+ alx_add_mc_addr(hw, ha->addr, mc_hash);
+
+ alx_write_mem32(hw, ALX_HASH_TBL0, mc_hash[0]);
+ alx_write_mem32(hw, ALX_HASH_TBL1, mc_hash[1]);
+ }
+
+ hw->rx_ctrl &= ~(ALX_MAC_CTRL_MULTIALL_EN | ALX_MAC_CTRL_PROMISC_EN);
+ if (netdev->flags & IFF_PROMISC)
+ hw->rx_ctrl |= ALX_MAC_CTRL_PROMISC_EN;
+ if (netdev->flags & IFF_ALLMULTI)
+ hw->rx_ctrl |= ALX_MAC_CTRL_MULTIALL_EN;
+
+ alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+}
+
+static void alx_set_rx_mode(struct net_device *netdev)
+{
+ __alx_set_rx_mode(netdev);
+}
+
+static int alx_set_mac_address(struct net_device *netdev, void *data)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+ struct sockaddr *addr = data;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ if (netdev->addr_assign_type & NET_ADDR_RANDOM)
+ netdev->addr_assign_type ^= NET_ADDR_RANDOM;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len);
+ alx_set_macaddr(hw, hw->mac_addr);
+
+ return 0;
+}
+
+static int alx_alloc_descriptors(struct alx_priv *alx)
+{
+ alx->txq.bufs = kcalloc(alx->tx_ringsz,
+ sizeof(struct alx_buffer),
+ GFP_KERNEL);
+ if (!alx->txq.bufs)
+ return -ENOMEM;
+
+ alx->rxq.bufs = kcalloc(alx->rx_ringsz,
+ sizeof(struct alx_buffer),
+ GFP_KERNEL);
+ if (!alx->rxq.bufs)
+ goto out_free;
+
+ /* physical tx/rx ring descriptors
+ *
+ * Allocate them as a single chunk because they must not cross a
+ * 4G boundary (hardware has a single register for high 32 bits
+ * of addresses only)
+ */
+ alx->descmem.size = sizeof(struct alx_txd) * alx->tx_ringsz +
+ sizeof(struct alx_rrd) * alx->rx_ringsz +
+ sizeof(struct alx_rfd) * alx->rx_ringsz;
+ alx->descmem.virt = dma_zalloc_coherent(&alx->hw.pdev->dev,
+ alx->descmem.size,
+ &alx->descmem.dma,
+ GFP_KERNEL);
+ if (!alx->descmem.virt)
+ goto out_free;
+
+ alx->txq.tpd = (void *)alx->descmem.virt;
+ alx->txq.tpd_dma = alx->descmem.dma;
+
+ /* alignment requirement for next block */
+ BUILD_BUG_ON(sizeof(struct alx_txd) % 8);
+
+ alx->rxq.rrd =
+ (void *)((u8 *)alx->descmem.virt +
+ sizeof(struct alx_txd) * alx->tx_ringsz);
+ alx->rxq.rrd_dma = alx->descmem.dma +
+ sizeof(struct alx_txd) * alx->tx_ringsz;
+
+ /* alignment requirement for next block */
+ BUILD_BUG_ON(sizeof(struct alx_rrd) % 8);
+
+ alx->rxq.rfd =
+ (void *)((u8 *)alx->descmem.virt +
+ sizeof(struct alx_txd) * alx->tx_ringsz +
+ sizeof(struct alx_rrd) * alx->rx_ringsz);
+ alx->rxq.rfd_dma = alx->descmem.dma +
+ sizeof(struct alx_txd) * alx->tx_ringsz +
+ sizeof(struct alx_rrd) * alx->rx_ringsz;
+
+ return 0;
+out_free:
+ kfree(alx->txq.bufs);
+ kfree(alx->rxq.bufs);
+ return -ENOMEM;
+}
+
+static int alx_alloc_rings(struct alx_priv *alx)
+{
+ int err;
+
+ err = alx_alloc_descriptors(alx);
+ if (err)
+ return err;
+
+ alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
+ alx->int_mask |= ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0;
+ alx->tx_ringsz = alx->tx_ringsz;
+
+ netif_napi_add(alx->dev, &alx->napi, alx_poll, 64);
+
+ alx_reinit_rings(alx);
+ return 0;
+}
+
+static void alx_free_rings(struct alx_priv *alx)
+{
+ netif_napi_del(&alx->napi);
+ alx_free_buffers(alx);
+
+ kfree(alx->txq.bufs);
+ kfree(alx->rxq.bufs);
+
+ dma_free_coherent(&alx->hw.pdev->dev,
+ alx->descmem.size,
+ alx->descmem.virt,
+ alx->descmem.dma);
+}
+
+static void alx_config_vector_mapping(struct alx_priv *alx)
+{
+ struct alx_hw *hw = &alx->hw;
+
+ alx_write_mem32(hw, ALX_MSI_MAP_TBL1, 0);
+ alx_write_mem32(hw, ALX_MSI_MAP_TBL2, 0);
+ alx_write_mem32(hw, ALX_MSI_ID_MAP, 0);
+}
+
+static void alx_irq_enable(struct alx_priv *alx)
+{
+ struct alx_hw *hw = &alx->hw;
+
+ /* level-1 interrupt switch */
+ alx_write_mem32(hw, ALX_ISR, 0);
+ alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+ alx_post_write(hw);
+}
+
+static void alx_irq_disable(struct alx_priv *alx)
+{
+ struct alx_hw *hw = &alx->hw;
+
+ alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS);
+ alx_write_mem32(hw, ALX_IMR, 0);
+ alx_post_write(hw);
+
+ synchronize_irq(alx->hw.pdev->irq);
+}
+
+static int alx_request_irq(struct alx_priv *alx)
+{
+ struct pci_dev *pdev = alx->hw.pdev;
+ struct alx_hw *hw = &alx->hw;
+ int err;
+ u32 msi_ctrl;
+
+ msi_ctrl = (hw->imt >> 1) << ALX_MSI_RETRANS_TM_SHIFT;
+
+ if (!pci_enable_msi(alx->hw.pdev)) {
+ alx->msi = true;
+
+ alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER,
+ msi_ctrl | ALX_MSI_MASK_SEL_LINE);
+ err = request_irq(pdev->irq, alx_intr_msi, 0,
+ alx->dev->name, alx);
+ if (!err)
+ goto out;
+ /* fall back to legacy interrupt */
+ pci_disable_msi(alx->hw.pdev);
+ }
+
+ alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER, 0);
+ err = request_irq(pdev->irq, alx_intr_legacy, IRQF_SHARED,
+ alx->dev->name, alx);
+out:
+ if (!err)
+ alx_config_vector_mapping(alx);
+ return err;
+}
+
+static void alx_free_irq(struct alx_priv *alx)
+{
+ struct pci_dev *pdev = alx->hw.pdev;
+
+ free_irq(pdev->irq, alx);
+
+ if (alx->msi) {
+ pci_disable_msi(alx->hw.pdev);
+ alx->msi = false;
+ }
+}
+
+static int alx_identify_hw(struct alx_priv *alx)
+{
+ struct alx_hw *hw = &alx->hw;
+ int rev = alx_hw_revision(hw);
+
+ if (rev > ALX_REV_C0)
+ return -EINVAL;
+
+ hw->max_dma_chnl = rev >= ALX_REV_B0 ? 4 : 2;
+
+ return 0;
+}
+
+static int alx_init_sw(struct alx_priv *alx)
+{
+ struct pci_dev *pdev = alx->hw.pdev;
+ struct alx_hw *hw = &alx->hw;
+ int err;
+
+ err = alx_identify_hw(alx);
+ if (err) {
+ dev_err(&pdev->dev, "unrecognized chip, aborting\n");
+ return err;
+ }
+
+ alx->hw.lnk_patch =
+ pdev->device == ALX_DEV_ID_AR8161 &&
+ pdev->subsystem_vendor == PCI_VENDOR_ID_ATTANSIC &&
+ pdev->subsystem_device == 0x0091 &&
+ pdev->revision == 0;
+
+ hw->smb_timer = 400;
+ hw->mtu = alx->dev->mtu;
+ alx->rxbuf_size = ALIGN(ALX_RAW_MTU(hw->mtu), 8);
+ alx->tx_ringsz = 256;
+ alx->rx_ringsz = 512;
+ hw->sleep_ctrl = ALX_SLEEP_WOL_MAGIC | ALX_SLEEP_WOL_PHY;
+ hw->imt = 200;
+ alx->int_mask = ALX_ISR_MISC;
+ hw->dma_chnl = hw->max_dma_chnl;
+ hw->ith_tpd = alx->tx_ringsz / 3;
+ hw->link_speed = SPEED_UNKNOWN;
+ hw->adv_cfg = ADVERTISED_Autoneg |
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_1000baseT_Full;
+ hw->flowctrl = ALX_FC_ANEG | ALX_FC_RX | ALX_FC_TX;
+
+ hw->rx_ctrl = ALX_MAC_CTRL_WOLSPED_SWEN |
+ ALX_MAC_CTRL_MHASH_ALG_HI5B |
+ ALX_MAC_CTRL_BRD_EN |
+ ALX_MAC_CTRL_PCRCE |
+ ALX_MAC_CTRL_CRCE |
+ ALX_MAC_CTRL_RXFC_EN |
+ ALX_MAC_CTRL_TXFC_EN |
+ 7 << ALX_MAC_CTRL_PRMBLEN_SHIFT;
+
+ return err;
+}
+
+
+static netdev_features_t alx_fix_features(struct net_device *netdev,
+ netdev_features_t features)
+{
+ if (netdev->mtu > ALX_MAX_TSO_PKT_SIZE)
+ features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+ return features;
+}
+
+static void alx_netif_stop(struct alx_priv *alx)
+{
+ alx->dev->trans_start = jiffies;
+ if (netif_carrier_ok(alx->dev)) {
+ netif_carrier_off(alx->dev);
+ netif_tx_disable(alx->dev);
+ napi_disable(&alx->napi);
+ }
+}
+
+static void alx_halt(struct alx_priv *alx)
+{
+ struct alx_hw *hw = &alx->hw;
+
+ alx_netif_stop(alx);
+ hw->link_speed = SPEED_UNKNOWN;
+
+ alx_reset_mac(hw);
+
+ /* disable l0s/l1 */
+ alx_enable_aspm(hw, false, false);
+ alx_irq_disable(alx);
+ alx_free_buffers(alx);
+}
+
+static void alx_configure(struct alx_priv *alx)
+{
+ struct alx_hw *hw = &alx->hw;
+
+ alx_configure_basic(hw);
+ alx_disable_rss(hw);
+ __alx_set_rx_mode(alx->dev);
+
+ alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl);
+}
+
+static void alx_activate(struct alx_priv *alx)
+{
+ /* hardware setting lost, restore it */
+ alx_reinit_rings(alx);
+ alx_configure(alx);
+
+ /* clear old interrupts */
+ alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS);
+
+ alx_irq_enable(alx);
+
+ alx_schedule_link_check(alx);
+}
+
+static void alx_reinit(struct alx_priv *alx)
+{
+ ASSERT_RTNL();
+
+ alx_halt(alx);
+ alx_activate(alx);
+}
+
+static int alx_change_mtu(struct net_device *netdev, int mtu)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ int max_frame = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+
+ if ((max_frame < ALX_MIN_FRAME_SIZE) ||
+ (max_frame > ALX_MAX_FRAME_SIZE))
+ return -EINVAL;
+
+ if (netdev->mtu == mtu)
+ return 0;
+
+ netdev->mtu = mtu;
+ alx->hw.mtu = mtu;
+ alx->rxbuf_size = mtu > ALX_DEF_RXBUF_SIZE ?
+ ALIGN(max_frame, 8) : ALX_DEF_RXBUF_SIZE;
+ netdev_update_features(netdev);
+ if (netif_running(netdev))
+ alx_reinit(alx);
+ return 0;
+}
+
+static void alx_netif_start(struct alx_priv *alx)
+{
+ netif_tx_wake_all_queues(alx->dev);
+ napi_enable(&alx->napi);
+ netif_carrier_on(alx->dev);
+}
+
+static int __alx_open(struct alx_priv *alx, bool resume)
+{
+ int err;
+
+ if (!resume)
+ netif_carrier_off(alx->dev);
+
+ err = alx_alloc_rings(alx);
+ if (err)
+ return err;
+
+ alx_configure(alx);
+
+ err = alx_request_irq(alx);
+ if (err)
+ goto out_free_rings;
+
+ /* clear old interrupts */
+ alx_write_mem32(&alx->hw, ALX_ISR, ~(u32)ALX_ISR_DIS);
+
+ alx_irq_enable(alx);
+
+ if (!resume)
+ netif_tx_start_all_queues(alx->dev);
+
+ alx_schedule_link_check(alx);
+ return 0;
+
+out_free_rings:
+ alx_free_rings(alx);
+ return err;
+}
+
+static void __alx_stop(struct alx_priv *alx)
+{
+ alx_halt(alx);
+ alx_free_irq(alx);
+ alx_free_rings(alx);
+}
+
+static const char *alx_speed_desc(u16 speed)
+{
+ switch (speed) {
+ case SPEED_1000 + DUPLEX_FULL:
+ return "1 Gbps Full";
+ case SPEED_100 + DUPLEX_FULL:
+ return "100 Mbps Full";
+ case SPEED_100 + DUPLEX_HALF:
+ return "100 Mbps Half";
+ case SPEED_10 + DUPLEX_FULL:
+ return "10 Mbps Full";
+ case SPEED_10 + DUPLEX_HALF:
+ return "10 Mbps Half";
+ default:
+ return "Unknown speed";
+ }
+}
+
+static void alx_check_link(struct alx_priv *alx)
+{
+ struct alx_hw *hw = &alx->hw;
+ unsigned long flags;
+ int speed, old_speed;
+ int err;
+
+ /* clear PHY internal interrupt status, otherwise the main
+ * interrupt status will be asserted forever
+ */
+ alx_clear_phy_intr(hw);
+
+ err = alx_get_phy_link(hw, &speed);
+ if (err < 0)
+ goto reset;
+
+ spin_lock_irqsave(&alx->irq_lock, flags);
+ alx->int_mask |= ALX_ISR_PHY;
+ alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+ spin_unlock_irqrestore(&alx->irq_lock, flags);
+
+ old_speed = hw->link_speed;
+
+ if (old_speed == speed)
+ return;
+ hw->link_speed = speed;
+
+ if (speed != SPEED_UNKNOWN) {
+ netif_info(alx, link, alx->dev,
+ "NIC Up: %s\n", alx_speed_desc(speed));
+ alx_post_phy_link(hw);
+ alx_enable_aspm(hw, true, true);
+ alx_start_mac(hw);
+
+ if (old_speed == SPEED_UNKNOWN)
+ alx_netif_start(alx);
+ } else {
+ /* link is now down */
+ alx_netif_stop(alx);
+ netif_info(alx, link, alx->dev, "Link Down\n");
+ err = alx_reset_mac(hw);
+ if (err)
+ goto reset;
+ alx_irq_disable(alx);
+
+ /* MAC reset causes all HW settings to be lost, restore all */
+ err = alx_reinit_rings(alx);
+ if (err)
+ goto reset;
+ alx_configure(alx);
+ alx_enable_aspm(hw, false, true);
+ alx_post_phy_link(hw);
+ alx_irq_enable(alx);
+ }
+
+ return;
+
+reset:
+ alx_schedule_reset(alx);
+}
+
+static int alx_open(struct net_device *netdev)
+{
+ return __alx_open(netdev_priv(netdev), false);
+}
+
+static int alx_stop(struct net_device *netdev)
+{
+ __alx_stop(netdev_priv(netdev));
+ return 0;
+}
+
+static int __alx_shutdown(struct pci_dev *pdev, bool *wol_en)
+{
+ struct alx_priv *alx = pci_get_drvdata(pdev);
+ struct net_device *netdev = alx->dev;
+ struct alx_hw *hw = &alx->hw;
+ int err, speed;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev))
+ __alx_stop(alx);
+
+#ifdef CONFIG_PM_SLEEP
+ err = pci_save_state(pdev);
+ if (err)
+ return err;
+#endif
+
+ err = alx_select_powersaving_speed(hw, &speed);
+ if (err)
+ return err;
+ err = alx_clear_phy_intr(hw);
+ if (err)
+ return err;
+ err = alx_pre_suspend(hw, speed);
+ if (err)
+ return err;
+ err = alx_config_wol(hw);
+ if (err)
+ return err;
+
+ *wol_en = false;
+ if (hw->sleep_ctrl & ALX_SLEEP_ACTIVE) {
+ netif_info(alx, wol, netdev,
+ "wol: ctrl=%X, speed=%X\n",
+ hw->sleep_ctrl, speed);
+ device_set_wakeup_enable(&pdev->dev, true);
+ *wol_en = true;
+ }
+
+ pci_disable_device(pdev);
+
+ return 0;
+}
+
+static void alx_shutdown(struct pci_dev *pdev)
+{
+ int err;
+ bool wol_en;
+
+ err = __alx_shutdown(pdev, &wol_en);
+ if (!err) {
+ pci_wake_from_d3(pdev, wol_en);
+ pci_set_power_state(pdev, PCI_D3hot);
+ } else {
+ dev_err(&pdev->dev, "shutdown fail %d\n", err);
+ }
+}
+
+static void alx_link_check(struct work_struct *work)
+{
+ struct alx_priv *alx;
+
+ alx = container_of(work, struct alx_priv, link_check_wk);
+
+ rtnl_lock();
+ alx_check_link(alx);
+ rtnl_unlock();
+}
+
+static void alx_reset(struct work_struct *work)
+{
+ struct alx_priv *alx = container_of(work, struct alx_priv, reset_wk);
+
+ rtnl_lock();
+ alx_reinit(alx);
+ rtnl_unlock();
+}
+
+static int alx_tx_csum(struct sk_buff *skb, struct alx_txd *first)
+{
+ u8 cso, css;
+
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
+ return 0;
+
+ cso = skb_checksum_start_offset(skb);
+ if (cso & 1)
+ return -EINVAL;
+
+ css = cso + skb->csum_offset;
+ first->word1 |= cpu_to_le32((cso >> 1) << TPD_CXSUMSTART_SHIFT);
+ first->word1 |= cpu_to_le32((css >> 1) << TPD_CXSUMOFFSET_SHIFT);
+ first->word1 |= cpu_to_le32(1 << TPD_CXSUM_EN_SHIFT);
+
+ return 0;
+}
+
+static int alx_map_tx_skb(struct alx_priv *alx, struct sk_buff *skb)
+{
+ struct alx_tx_queue *txq = &alx->txq;
+ struct alx_txd *tpd, *first_tpd;
+ dma_addr_t dma;
+ int maplen, f, first_idx = txq->write_idx;
+
+ first_tpd = &txq->tpd[txq->write_idx];
+ tpd = first_tpd;
+
+ maplen = skb_headlen(skb);
+ dma = dma_map_single(&alx->hw.pdev->dev, skb->data, maplen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&alx->hw.pdev->dev, dma))
+ goto err_dma;
+
+ dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen);
+ dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma);
+
+ tpd->adrl.addr = cpu_to_le64(dma);
+ tpd->len = cpu_to_le16(maplen);
+
+ for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
+ struct skb_frag_struct *frag;
+
+ frag = &skb_shinfo(skb)->frags[f];
+
+ if (++txq->write_idx == alx->tx_ringsz)
+ txq->write_idx = 0;
+ tpd = &txq->tpd[txq->write_idx];
+
+ tpd->word1 = first_tpd->word1;
+
+ maplen = skb_frag_size(frag);
+ dma = skb_frag_dma_map(&alx->hw.pdev->dev, frag, 0,
+ maplen, DMA_TO_DEVICE);
+ if (dma_mapping_error(&alx->hw.pdev->dev, dma))
+ goto err_dma;
+ dma_unmap_len_set(&txq->bufs[txq->write_idx], size, maplen);
+ dma_unmap_addr_set(&txq->bufs[txq->write_idx], dma, dma);
+
+ tpd->adrl.addr = cpu_to_le64(dma);
+ tpd->len = cpu_to_le16(maplen);
+ }
+
+ /* last TPD, set EOP flag and store skb */
+ tpd->word1 |= cpu_to_le32(1 << TPD_EOP_SHIFT);
+ txq->bufs[txq->write_idx].skb = skb;
+
+ if (++txq->write_idx == alx->tx_ringsz)
+ txq->write_idx = 0;
+
+ return 0;
+
+err_dma:
+ f = first_idx;
+ while (f != txq->write_idx) {
+ alx_free_txbuf(alx, f);
+ if (++f == alx->tx_ringsz)
+ f = 0;
+ }
+ return -ENOMEM;
+}
+
+static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
+ struct net_device *netdev)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_tx_queue *txq = &alx->txq;
+ struct alx_txd *first;
+ int tpdreq = skb_shinfo(skb)->nr_frags + 1;
+
+ if (alx_tpd_avail(alx) < tpdreq) {
+ netif_stop_queue(alx->dev);
+ goto drop;
+ }
+
+ first = &txq->tpd[txq->write_idx];
+ memset(first, 0, sizeof(*first));
+
+ if (alx_tx_csum(skb, first))
+ goto drop;
+
+ if (alx_map_tx_skb(alx, skb) < 0)
+ goto drop;
+
+ netdev_sent_queue(alx->dev, skb->len);
+
+ /* flush updates before updating hardware */
+ wmb();
+ alx_write_mem16(&alx->hw, ALX_TPD_PRI0_PIDX, txq->write_idx);
+
+ if (alx_tpd_avail(alx) < alx->tx_ringsz/8)
+ netif_stop_queue(alx->dev);
+
+ return NETDEV_TX_OK;
+
+drop:
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static void alx_tx_timeout(struct net_device *dev)
+{
+ struct alx_priv *alx = netdev_priv(dev);
+
+ alx_schedule_reset(alx);
+}
+
+static int alx_mdio_read(struct net_device *netdev,
+ int prtad, int devad, u16 addr)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+ u16 val;
+ int err;
+
+ if (prtad != hw->mdio.prtad)
+ return -EINVAL;
+
+ if (devad == MDIO_DEVAD_NONE)
+ err = alx_read_phy_reg(hw, addr, &val);
+ else
+ err = alx_read_phy_ext(hw, devad, addr, &val);
+
+ if (err)
+ return err;
+ return val;
+}
+
+static int alx_mdio_write(struct net_device *netdev,
+ int prtad, int devad, u16 addr, u16 val)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+ struct alx_hw *hw = &alx->hw;
+
+ if (prtad != hw->mdio.prtad)
+ return -EINVAL;
+
+ if (devad == MDIO_DEVAD_NONE)
+ return alx_write_phy_reg(hw, addr, val);
+
+ return alx_write_phy_ext(hw, devad, addr, val);
+}
+
+static int alx_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+
+ if (!netif_running(netdev))
+ return -EAGAIN;
+
+ return mdio_mii_ioctl(&alx->hw.mdio, if_mii(ifr), cmd);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void alx_poll_controller(struct net_device *netdev)
+{
+ struct alx_priv *alx = netdev_priv(netdev);
+
+ if (alx->msi)
+ alx_intr_msi(0, alx);
+ else
+ alx_intr_legacy(0, alx);
+}
+#endif
+
+static const struct net_device_ops alx_netdev_ops = {
+ .ndo_open = alx_open,
+ .ndo_stop = alx_stop,
+ .ndo_start_xmit = alx_start_xmit,
+ .ndo_set_rx_mode = alx_set_rx_mode,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = alx_set_mac_address,
+ .ndo_change_mtu = alx_change_mtu,
+ .ndo_do_ioctl = alx_ioctl,
+ .ndo_tx_timeout = alx_tx_timeout,
+ .ndo_fix_features = alx_fix_features,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = alx_poll_controller,
+#endif
+};
+
+static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *netdev;
+ struct alx_priv *alx;
+ struct alx_hw *hw;
+ bool phy_configured;
+ int bars, pm_cap, err;
+
+ err = pci_enable_device_mem(pdev);
+ if (err)
+ return err;
+
+ /* The alx chip can DMA to 64-bit addresses, but it uses a single
+ * shared register for the high 32 bits, so only a single, aligned,
+ * 4 GB physical address range can be used for descriptors.
+ */
+ if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
+ !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+ dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n");
+ } else {
+ err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (err) {
+ err = dma_set_coherent_mask(&pdev->dev,
+ DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&pdev->dev,
+ "No usable DMA config, aborting\n");
+ goto out_pci_disable;
+ }
+ }
+ }
+
+ bars = pci_select_bars(pdev, IORESOURCE_MEM);
+ err = pci_request_selected_regions(pdev, bars, alx_drv_name);
+ if (err) {
+ dev_err(&pdev->dev,
+ "pci_request_selected_regions failed(bars:%d)\n", bars);
+ goto out_pci_disable;
+ }
+
+ pci_enable_pcie_error_reporting(pdev);
+ pci_set_master(pdev);
+
+ pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pm_cap == 0) {
+ dev_err(&pdev->dev,
+ "Can't find power management capability, aborting\n");
+ err = -EIO;
+ goto out_pci_release;
+ }
+
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err)
+ goto out_pci_release;
+
+ netdev = alloc_etherdev(sizeof(*alx));
+ if (!netdev) {
+ err = -ENOMEM;
+ goto out_pci_release;
+ }
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ alx = netdev_priv(netdev);
+ alx->dev = netdev;
+ alx->hw.pdev = pdev;
+ alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP |
+ NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR | NETIF_MSG_WOL;
+ hw = &alx->hw;
+ pci_set_drvdata(pdev, alx);
+
+ hw->hw_addr = pci_ioremap_bar(pdev, 0);
+ if (!hw->hw_addr) {
+ dev_err(&pdev->dev, "cannot map device registers\n");
+ err = -EIO;
+ goto out_free_netdev;
+ }
+
+ netdev->netdev_ops = &alx_netdev_ops;
+ SET_ETHTOOL_OPS(netdev, &alx_ethtool_ops);
+ netdev->irq = pdev->irq;
+ netdev->watchdog_timeo = ALX_WATCHDOG_TIME;
+
+ if (ent->driver_data & ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG)
+ pdev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG;
+
+ err = alx_init_sw(alx);
+ if (err) {
+ dev_err(&pdev->dev, "net device private data init failed\n");
+ goto out_unmap;
+ }
+
+ alx_reset_pcie(hw);
+
+ phy_configured = alx_phy_configured(hw);
+
+ if (!phy_configured)
+ alx_reset_phy(hw);
+
+ err = alx_reset_mac(hw);
+ if (err) {
+ dev_err(&pdev->dev, "MAC Reset failed, error = %d\n", err);
+ goto out_unmap;
+ }
+
+ /* setup link to put it in a known good starting state */
+ if (!phy_configured) {
+ err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl);
+ if (err) {
+ dev_err(&pdev->dev,
+ "failed to configure PHY speed/duplex (err=%d)\n",
+ err);
+ goto out_unmap;
+ }
+ }
+
+ netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+
+ if (alx_get_perm_macaddr(hw, hw->perm_addr)) {
+ dev_warn(&pdev->dev,
+ "Invalid permanent address programmed, using random one\n");
+ eth_hw_addr_random(netdev);
+ memcpy(hw->perm_addr, netdev->dev_addr, netdev->addr_len);
+ }
+
+ memcpy(hw->mac_addr, hw->perm_addr, ETH_ALEN);
+ memcpy(netdev->dev_addr, hw->mac_addr, ETH_ALEN);
+ memcpy(netdev->perm_addr, hw->perm_addr, ETH_ALEN);
+
+ hw->mdio.prtad = 0;
+ hw->mdio.mmds = 0;
+ hw->mdio.dev = netdev;
+ hw->mdio.mode_support = MDIO_SUPPORTS_C45 |
+ MDIO_SUPPORTS_C22 |
+ MDIO_EMULATE_C22;
+ hw->mdio.mdio_read = alx_mdio_read;
+ hw->mdio.mdio_write = alx_mdio_write;
+
+ if (!alx_get_phy_info(hw)) {
+ dev_err(&pdev->dev, "failed to identify PHY\n");
+ err = -EIO;
+ goto out_unmap;
+ }
+
+ INIT_WORK(&alx->link_check_wk, alx_link_check);
+ INIT_WORK(&alx->reset_wk, alx_reset);
+ spin_lock_init(&alx->hw.mdio_lock);
+ spin_lock_init(&alx->irq_lock);
+
+ netif_carrier_off(netdev);
+
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pdev->dev, "register netdevice failed\n");
+ goto out_unmap;
+ }
+
+ device_set_wakeup_enable(&pdev->dev, hw->sleep_ctrl);
+
+ netdev_info(netdev,
+ "Qualcomm Atheros AR816x/AR817x Ethernet [%pM]\n",
+ netdev->dev_addr);
+
+ return 0;
+
+out_unmap:
+ iounmap(hw->hw_addr);
+out_free_netdev:
+ free_netdev(netdev);
+out_pci_release:
+ pci_release_selected_regions(pdev, bars);
+out_pci_disable:
+ pci_disable_device(pdev);
+ return err;
+}
+
+static void alx_remove(struct pci_dev *pdev)
+{
+ struct alx_priv *alx = pci_get_drvdata(pdev);
+ struct alx_hw *hw = &alx->hw;
+
+ cancel_work_sync(&alx->link_check_wk);
+ cancel_work_sync(&alx->reset_wk);
+
+ /* restore permanent mac address */
+ alx_set_macaddr(hw, hw->perm_addr);
+
+ unregister_netdev(alx->dev);
+ iounmap(hw->hw_addr);
+ pci_release_selected_regions(pdev,
+ pci_select_bars(pdev, IORESOURCE_MEM));
+
+ pci_disable_pcie_error_reporting(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ free_netdev(alx->dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int alx_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int err;
+ bool wol_en;
+
+ err = __alx_shutdown(pdev, &wol_en);
+ if (err) {
+ dev_err(&pdev->dev, "shutdown fail in suspend %d\n", err);
+ return err;
+ }
+
+ if (wol_en) {
+ pci_prepare_to_sleep(pdev);
+ } else {
+ pci_wake_from_d3(pdev, false);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
+
+ return 0;
+}
+
+static int alx_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct alx_priv *alx = pci_get_drvdata(pdev);
+ struct net_device *netdev = alx->dev;
+ struct alx_hw *hw = &alx->hw;
+ int err;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_save_state(pdev);
+
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ hw->link_speed = SPEED_UNKNOWN;
+ alx->int_mask = ALX_ISR_MISC;
+
+ alx_reset_pcie(hw);
+ alx_reset_phy(hw);
+
+ err = alx_reset_mac(hw);
+ if (err) {
+ netif_err(alx, hw, alx->dev,
+ "resume:reset_mac fail %d\n", err);
+ return -EIO;
+ }
+
+ err = alx_setup_speed_duplex(hw, hw->adv_cfg, hw->flowctrl);
+ if (err) {
+ netif_err(alx, hw, alx->dev,
+ "resume:setup_speed_duplex fail %d\n", err);
+ return -EIO;
+ }
+
+ if (netif_running(netdev)) {
+ err = __alx_open(alx, true);
+ if (err)
+ return err;
+ }
+
+ netif_device_attach(netdev);
+
+ return err;
+}
+#endif
+
+static pci_ers_result_t alx_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct alx_priv *alx = pci_get_drvdata(pdev);
+ struct net_device *netdev = alx->dev;
+ pci_ers_result_t rc = PCI_ERS_RESULT_NEED_RESET;
+
+ dev_info(&pdev->dev, "pci error detected\n");
+
+ rtnl_lock();
+
+ if (netif_running(netdev)) {
+ netif_device_detach(netdev);
+ alx_halt(alx);
+ }
+
+ if (state == pci_channel_io_perm_failure)
+ rc = PCI_ERS_RESULT_DISCONNECT;
+ else
+ pci_disable_device(pdev);
+
+ rtnl_unlock();
+
+ return rc;
+}
+
+static pci_ers_result_t alx_pci_error_slot_reset(struct pci_dev *pdev)
+{
+ struct alx_priv *alx = pci_get_drvdata(pdev);
+ struct alx_hw *hw = &alx->hw;
+ pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT;
+
+ dev_info(&pdev->dev, "pci error slot reset\n");
+
+ rtnl_lock();
+
+ if (pci_enable_device(pdev)) {
+ dev_err(&pdev->dev, "Failed to re-enable PCI device after reset\n");
+ goto out;
+ }
+
+ pci_set_master(pdev);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ alx_reset_pcie(hw);
+ if (!alx_reset_mac(hw))
+ rc = PCI_ERS_RESULT_RECOVERED;
+out:
+ pci_cleanup_aer_uncorrect_error_status(pdev);
+
+ rtnl_unlock();
+
+ return rc;
+}
+
+static void alx_pci_error_resume(struct pci_dev *pdev)
+{
+ struct alx_priv *alx = pci_get_drvdata(pdev);
+ struct net_device *netdev = alx->dev;
+
+ dev_info(&pdev->dev, "pci error resume\n");
+
+ rtnl_lock();
+
+ if (netif_running(netdev)) {
+ alx_activate(alx);
+ netif_device_attach(netdev);
+ }
+
+ rtnl_unlock();
+}
+
+static const struct pci_error_handlers alx_err_handlers = {
+ .error_detected = alx_pci_error_detected,
+ .slot_reset = alx_pci_error_slot_reset,
+ .resume = alx_pci_error_resume,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static SIMPLE_DEV_PM_OPS(alx_pm_ops, alx_suspend, alx_resume);
+#define ALX_PM_OPS (&alx_pm_ops)
+#else
+#define ALX_PM_OPS NULL
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(alx_pci_tbl) = {
+ { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8161),
+ .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
+ { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200),
+ .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
+ { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162),
+ .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
+ { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) },
+ { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8172) },
+ {}
+};
+
+static struct pci_driver alx_driver = {
+ .name = alx_drv_name,
+ .id_table = alx_pci_tbl,
+ .probe = alx_probe,
+ .remove = alx_remove,
+ .shutdown = alx_shutdown,
+ .err_handler = &alx_err_handlers,
+ .driver.pm = ALX_PM_OPS,
+};
+
+module_pci_driver(alx_driver);
+MODULE_DEVICE_TABLE(pci, alx_pci_tbl);
+MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
+MODULE_AUTHOR("Qualcomm Corporation, <nic-devel@qualcomm.com>");
+MODULE_DESCRIPTION(
+ "Qualcomm Atheros(R) AR816x/AR817x PCI-E Ethernet Network Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/atheros/alx/reg.h b/drivers/net/ethernet/atheros/alx/reg.h
new file mode 100644
index 0000000..e4358c9
--- /dev/null
+++ b/drivers/net/ethernet/atheros/alx/reg.h
@@ -0,0 +1,810 @@
+/*
+ * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is free software: you may copy, redistribute 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 file 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, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ALX_REG_H
+#define ALX_REG_H
+
+#define ALX_DEV_ID_AR8161 0x1091
+#define ALX_DEV_ID_E2200 0xe091
+#define ALX_DEV_ID_AR8162 0x1090
+#define ALX_DEV_ID_AR8171 0x10A1
+#define ALX_DEV_ID_AR8172 0x10A0
+
+/* rev definition,
+ * bit(0): with xD support
+ * bit(1): with Card Reader function
+ * bit(7:2): real revision
+ */
+#define ALX_PCI_REVID_SHIFT 3
+#define ALX_REV_A0 0
+#define ALX_REV_A1 1
+#define ALX_REV_B0 2
+#define ALX_REV_C0 3
+
+#define ALX_DEV_CTRL 0x0060
+#define ALX_DEV_CTRL_MAXRRS_MIN 2
+
+#define ALX_MSIX_MASK 0x0090
+
+#define ALX_UE_SVRT 0x010C
+#define ALX_UE_SVRT_FCPROTERR BIT(13)
+#define ALX_UE_SVRT_DLPROTERR BIT(4)
+
+/* eeprom & flash load register */
+#define ALX_EFLD 0x0204
+#define ALX_EFLD_F_EXIST BIT(10)
+#define ALX_EFLD_E_EXIST BIT(9)
+#define ALX_EFLD_STAT BIT(5)
+#define ALX_EFLD_START BIT(0)
+
+/* eFuse load register */
+#define ALX_SLD 0x0218
+#define ALX_SLD_STAT BIT(12)
+#define ALX_SLD_START BIT(11)
+#define ALX_SLD_MAX_TO 100
+
+#define ALX_PDLL_TRNS1 0x1104
+#define ALX_PDLL_TRNS1_D3PLLOFF_EN BIT(11)
+
+#define ALX_PMCTRL 0x12F8
+#define ALX_PMCTRL_HOTRST_WTEN BIT(31)
+/* bit30: L0s/L1 controlled by MAC based on throughput(setting in 15A0) */
+#define ALX_PMCTRL_ASPM_FCEN BIT(30)
+#define ALX_PMCTRL_SADLY_EN BIT(29)
+#define ALX_PMCTRL_LCKDET_TIMER_MASK 0xF
+#define ALX_PMCTRL_LCKDET_TIMER_SHIFT 24
+#define ALX_PMCTRL_LCKDET_TIMER_DEF 0xC
+/* bit[23:20] if pm_request_l1 time > @, then enter L0s not L1 */
+#define ALX_PMCTRL_L1REQ_TO_MASK 0xF
+#define ALX_PMCTRL_L1REQ_TO_SHIFT 20
+#define ALX_PMCTRL_L1REG_TO_DEF 0xF
+#define ALX_PMCTRL_TXL1_AFTER_L0S BIT(19)
+#define ALX_PMCTRL_L1_TIMER_MASK 0x7
+#define ALX_PMCTRL_L1_TIMER_SHIFT 16
+#define ALX_PMCTRL_L1_TIMER_16US 4
+#define ALX_PMCTRL_RCVR_WT_1US BIT(15)
+/* bit13: enable pcie clk switch in L1 state */
+#define ALX_PMCTRL_L1_CLKSW_EN BIT(13)
+#define ALX_PMCTRL_L0S_EN BIT(12)
+#define ALX_PMCTRL_RXL1_AFTER_L0S BIT(11)
+#define ALX_PMCTRL_L1_BUFSRX_EN BIT(7)
+/* bit6: power down serdes RX */
+#define ALX_PMCTRL_L1_SRDSRX_PWD BIT(6)
+#define ALX_PMCTRL_L1_SRDSPLL_EN BIT(5)
+#define ALX_PMCTRL_L1_SRDS_EN BIT(4)
+#define ALX_PMCTRL_L1_EN BIT(3)
+
+/*******************************************************/
+/* following registers are mapped only to memory space */
+/*******************************************************/
+
+#define ALX_MASTER 0x1400
+/* bit12: 1:alwys select pclk from serdes, not sw to 25M */
+#define ALX_MASTER_PCLKSEL_SRDS BIT(12)
+/* bit11: irq moduration for rx */
+#define ALX_MASTER_IRQMOD2_EN BIT(11)
+/* bit10: irq moduration for tx/rx */
+#define ALX_MASTER_IRQMOD1_EN BIT(10)
+#define ALX_MASTER_SYSALVTIMER_EN BIT(7)
+#define ALX_MASTER_OOB_DIS BIT(6)
+/* bit5: wakeup without pcie clk */
+#define ALX_MASTER_WAKEN_25M BIT(5)
+/* bit0: MAC & DMA reset */
+#define ALX_MASTER_DMA_MAC_RST BIT(0)
+#define ALX_DMA_MAC_RST_TO 50
+
+#define ALX_IRQ_MODU_TIMER 0x1408
+#define ALX_IRQ_MODU_TIMER1_MASK 0xFFFF
+#define ALX_IRQ_MODU_TIMER1_SHIFT 0
+
+#define ALX_PHY_CTRL 0x140C
+#define ALX_PHY_CTRL_100AB_EN BIT(17)
+/* bit14: affect MAC & PHY, go to low power sts */
+#define ALX_PHY_CTRL_POWER_DOWN BIT(14)
+/* bit13: 1:pll always ON, 0:can switch in lpw */
+#define ALX_PHY_CTRL_PLL_ON BIT(13)
+#define ALX_PHY_CTRL_RST_ANALOG BIT(12)
+#define ALX_PHY_CTRL_HIB_PULSE BIT(11)
+#define ALX_PHY_CTRL_HIB_EN BIT(10)
+#define ALX_PHY_CTRL_IDDQ BIT(7)
+#define ALX_PHY_CTRL_GATE_25M BIT(5)
+#define ALX_PHY_CTRL_LED_MODE BIT(2)
+/* bit0: out of dsp RST state */
+#define ALX_PHY_CTRL_DSPRST_OUT BIT(0)
+#define ALX_PHY_CTRL_DSPRST_TO 80
+#define ALX_PHY_CTRL_CLS (ALX_PHY_CTRL_LED_MODE | \
+ ALX_PHY_CTRL_100AB_EN | \
+ ALX_PHY_CTRL_PLL_ON)
+
+#define ALX_MAC_STS 0x1410
+#define ALX_MAC_STS_TXQ_BUSY BIT(3)
+#define ALX_MAC_STS_RXQ_BUSY BIT(2)
+#define ALX_MAC_STS_TXMAC_BUSY BIT(1)
+#define ALX_MAC_STS_RXMAC_BUSY BIT(0)
+#define ALX_MAC_STS_IDLE (ALX_MAC_STS_TXQ_BUSY | \
+ ALX_MAC_STS_RXQ_BUSY | \
+ ALX_MAC_STS_TXMAC_BUSY | \
+ ALX_MAC_STS_RXMAC_BUSY)
+
+#define ALX_MDIO 0x1414
+#define ALX_MDIO_MODE_EXT BIT(30)
+#define ALX_MDIO_BUSY BIT(27)
+#define ALX_MDIO_CLK_SEL_MASK 0x7
+#define ALX_MDIO_CLK_SEL_SHIFT 24
+#define ALX_MDIO_CLK_SEL_25MD4 0
+#define ALX_MDIO_CLK_SEL_25MD128 7
+#define ALX_MDIO_START BIT(23)
+#define ALX_MDIO_SPRES_PRMBL BIT(22)
+/* bit21: 1:read,0:write */
+#define ALX_MDIO_OP_READ BIT(21)
+#define ALX_MDIO_REG_MASK 0x1F
+#define ALX_MDIO_REG_SHIFT 16
+#define ALX_MDIO_DATA_MASK 0xFFFF
+#define ALX_MDIO_DATA_SHIFT 0
+#define ALX_MDIO_MAX_AC_TO 120
+
+#define ALX_MDIO_EXTN 0x1448
+#define ALX_MDIO_EXTN_DEVAD_MASK 0x1F
+#define ALX_MDIO_EXTN_DEVAD_SHIFT 16
+#define ALX_MDIO_EXTN_REG_MASK 0xFFFF
+#define ALX_MDIO_EXTN_REG_SHIFT 0
+
+#define ALX_SERDES 0x1424
+#define ALX_SERDES_PHYCLK_SLWDWN BIT(18)
+#define ALX_SERDES_MACCLK_SLWDWN BIT(17)
+
+#define ALX_LPI_CTRL 0x1440
+#define ALX_LPI_CTRL_EN BIT(0)
+
+/* for B0+, bit[13..] for C0+ */
+#define ALX_HRTBT_EXT_CTRL 0x1AD0
+#define L1F_HRTBT_EXT_CTRL_PERIOD_HIGH_MASK 0x3F
+#define L1F_HRTBT_EXT_CTRL_PERIOD_HIGH_SHIFT 24
+#define L1F_HRTBT_EXT_CTRL_SWOI_STARTUP_PKT_EN BIT(23)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_FRAGMENTED BIT(22)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_FRAGMENTED BIT(21)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_KEEPALIVE_EN BIT(20)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_HAS_VLAN BIT(19)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_IS_8023 BIT(18)
+#define L1F_HRTBT_EXT_CTRL_IOAC_1_IS_IPV6 BIT(17)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_KEEPALIVE_EN BIT(16)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_HAS_VLAN BIT(15)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_IS_8023 BIT(14)
+#define L1F_HRTBT_EXT_CTRL_IOAC_2_IS_IPV6 BIT(13)
+#define ALX_HRTBT_EXT_CTRL_NS_EN BIT(12)
+#define ALX_HRTBT_EXT_CTRL_FRAG_LEN_MASK 0xFF
+#define ALX_HRTBT_EXT_CTRL_FRAG_LEN_SHIFT 4
+#define ALX_HRTBT_EXT_CTRL_IS_8023 BIT(3)
+#define ALX_HRTBT_EXT_CTRL_IS_IPV6 BIT(2)
+#define ALX_HRTBT_EXT_CTRL_WAKEUP_EN BIT(1)
+#define ALX_HRTBT_EXT_CTRL_ARP_EN BIT(0)
+
+#define ALX_HRTBT_REM_IPV4_ADDR 0x1AD4
+#define ALX_HRTBT_HOST_IPV4_ADDR 0x1478
+#define ALX_HRTBT_REM_IPV6_ADDR3 0x1AD8
+#define ALX_HRTBT_REM_IPV6_ADDR2 0x1ADC
+#define ALX_HRTBT_REM_IPV6_ADDR1 0x1AE0
+#define ALX_HRTBT_REM_IPV6_ADDR0 0x1AE4
+
+/* 1B8C ~ 1B94 for C0+ */
+#define ALX_SWOI_ACER_CTRL 0x1B8C
+#define ALX_SWOI_ORIG_ACK_NAK_EN BIT(20)
+#define ALX_SWOI_ORIG_ACK_NAK_PKT_LEN_MASK 0XFF
+#define ALX_SWOI_ORIG_ACK_NAK_PKT_LEN_SHIFT 12
+#define ALX_SWOI_ORIG_ACK_ADDR_MASK 0XFFF
+#define ALX_SWOI_ORIG_ACK_ADDR_SHIFT 0
+
+#define ALX_SWOI_IOAC_CTRL_2 0x1B90
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_FRAG_LEN_MASK 0xFF
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_FRAG_LEN_SHIFT 24
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_PKT_LEN_MASK 0xFFF
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_PKT_LEN_SHIFT 12
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_HDR_ADDR_MASK 0xFFF
+#define ALX_SWOI_IOAC_CTRL_2_SWOI_1_HDR_ADDR_SHIFT 0
+
+#define ALX_SWOI_IOAC_CTRL_3 0x1B94
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_FRAG_LEN_MASK 0xFF
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_FRAG_LEN_SHIFT 24
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_PKT_LEN_MASK 0xFFF
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_PKT_LEN_SHIFT 12
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_HDR_ADDR_MASK 0xFFF
+#define ALX_SWOI_IOAC_CTRL_3_SWOI_2_HDR_ADDR_SHIFT 0
+
+/* for B0 */
+#define ALX_IDLE_DECISN_TIMER 0x1474
+/* 1ms */
+#define ALX_IDLE_DECISN_TIMER_DEF 0x400
+
+#define ALX_MAC_CTRL 0x1480
+#define ALX_MAC_CTRL_FAST_PAUSE BIT(31)
+#define ALX_MAC_CTRL_WOLSPED_SWEN BIT(30)
+/* bit29: 1:legacy(hi5b), 0:marvl(lo5b)*/
+#define ALX_MAC_CTRL_MHASH_ALG_HI5B BIT(29)
+#define ALX_MAC_CTRL_BRD_EN BIT(26)
+#define ALX_MAC_CTRL_MULTIALL_EN BIT(25)
+#define ALX_MAC_CTRL_SPEED_MASK 0x3
+#define ALX_MAC_CTRL_SPEED_SHIFT 20
+#define ALX_MAC_CTRL_SPEED_10_100 1
+#define ALX_MAC_CTRL_SPEED_1000 2
+#define ALX_MAC_CTRL_PROMISC_EN BIT(15)
+#define ALX_MAC_CTRL_VLANSTRIP BIT(14)
+#define ALX_MAC_CTRL_PRMBLEN_MASK 0xF
+#define ALX_MAC_CTRL_PRMBLEN_SHIFT 10
+#define ALX_MAC_CTRL_PCRCE BIT(7)
+#define ALX_MAC_CTRL_CRCE BIT(6)
+#define ALX_MAC_CTRL_FULLD BIT(5)
+#define ALX_MAC_CTRL_RXFC_EN BIT(3)
+#define ALX_MAC_CTRL_TXFC_EN BIT(2)
+#define ALX_MAC_CTRL_RX_EN BIT(1)
+#define ALX_MAC_CTRL_TX_EN BIT(0)
+
+#define ALX_STAD0 0x1488
+#define ALX_STAD1 0x148C
+
+#define ALX_HASH_TBL0 0x1490
+#define ALX_HASH_TBL1 0x1494
+
+#define ALX_MTU 0x149C
+#define ALX_MTU_JUMBO_TH 1514
+#define ALX_MTU_STD_ALGN 1536
+
+#define ALX_SRAM5 0x1524
+#define ALX_SRAM_RXF_LEN_MASK 0xFFF
+#define ALX_SRAM_RXF_LEN_SHIFT 0
+#define ALX_SRAM_RXF_LEN_8K (8*1024)
+
+#define ALX_SRAM9 0x1534
+#define ALX_SRAM_LOAD_PTR BIT(0)
+
+#define ALX_RX_BASE_ADDR_HI 0x1540
+
+#define ALX_TX_BASE_ADDR_HI 0x1544
+
+#define ALX_RFD_ADDR_LO 0x1550
+#define ALX_RFD_RING_SZ 0x1560
+#define ALX_RFD_BUF_SZ 0x1564
+
+#define ALX_RRD_ADDR_LO 0x1568
+#define ALX_RRD_RING_SZ 0x1578
+
+/* pri3: highest, pri0: lowest */
+#define ALX_TPD_PRI3_ADDR_LO 0x14E4
+#define ALX_TPD_PRI2_ADDR_LO 0x14E0
+#define ALX_TPD_PRI1_ADDR_LO 0x157C
+#define ALX_TPD_PRI0_ADDR_LO 0x1580
+
+/* producer index is 16bit */
+#define ALX_TPD_PRI3_PIDX 0x1618
+#define ALX_TPD_PRI2_PIDX 0x161A
+#define ALX_TPD_PRI1_PIDX 0x15F0
+#define ALX_TPD_PRI0_PIDX 0x15F2
+
+/* consumer index is 16bit */
+#define ALX_TPD_PRI3_CIDX 0x161C
+#define ALX_TPD_PRI2_CIDX 0x161E
+#define ALX_TPD_PRI1_CIDX 0x15F4
+#define ALX_TPD_PRI0_CIDX 0x15F6
+
+#define ALX_TPD_RING_SZ 0x1584
+
+#define ALX_TXQ0 0x1590
+#define ALX_TXQ0_TXF_BURST_PREF_MASK 0xFFFF
+#define ALX_TXQ0_TXF_BURST_PREF_SHIFT 16
+#define ALX_TXQ_TXF_BURST_PREF_DEF 0x200
+#define ALX_TXQ0_LSO_8023_EN BIT(7)
+#define ALX_TXQ0_MODE_ENHANCE BIT(6)
+#define ALX_TXQ0_EN BIT(5)
+#define ALX_TXQ0_SUPT_IPOPT BIT(4)
+#define ALX_TXQ0_TPD_BURSTPREF_MASK 0xF
+#define ALX_TXQ0_TPD_BURSTPREF_SHIFT 0
+#define ALX_TXQ_TPD_BURSTPREF_DEF 5
+
+#define ALX_TXQ1 0x1594
+/* bit11: drop large packet, len > (rfd buf) */
+#define ALX_TXQ1_ERRLGPKT_DROP_EN BIT(11)
+#define ALX_TXQ1_JUMBO_TSO_TH (7*1024)
+
+#define ALX_RXQ0 0x15A0
+#define ALX_RXQ0_EN BIT(31)
+#define ALX_RXQ0_RSS_HASH_EN BIT(29)
+#define ALX_RXQ0_RSS_MODE_MASK 0x3
+#define ALX_RXQ0_RSS_MODE_SHIFT 26
+#define ALX_RXQ0_RSS_MODE_DIS 0
+#define ALX_RXQ0_RSS_MODE_MQMI 3
+#define ALX_RXQ0_NUM_RFD_PREF_MASK 0x3F
+#define ALX_RXQ0_NUM_RFD_PREF_SHIFT 20
+#define ALX_RXQ0_NUM_RFD_PREF_DEF 8
+#define ALX_RXQ0_IDT_TBL_SIZE_MASK 0x1FF
+#define ALX_RXQ0_IDT_TBL_SIZE_SHIFT 8
+#define ALX_RXQ0_IDT_TBL_SIZE_DEF 0x100
+#define ALX_RXQ0_IDT_TBL_SIZE_NORMAL 128
+#define ALX_RXQ0_IPV6_PARSE_EN BIT(7)
+#define ALX_RXQ0_RSS_HSTYP_MASK 0xF
+#define ALX_RXQ0_RSS_HSTYP_SHIFT 2
+#define ALX_RXQ0_RSS_HSTYP_IPV6_TCP_EN BIT(5)
+#define ALX_RXQ0_RSS_HSTYP_IPV6_EN BIT(4)
+#define ALX_RXQ0_RSS_HSTYP_IPV4_TCP_EN BIT(3)
+#define ALX_RXQ0_RSS_HSTYP_IPV4_EN BIT(2)
+#define ALX_RXQ0_RSS_HSTYP_ALL (ALX_RXQ0_RSS_HSTYP_IPV6_TCP_EN | \
+ ALX_RXQ0_RSS_HSTYP_IPV4_TCP_EN | \
+ ALX_RXQ0_RSS_HSTYP_IPV6_EN | \
+ ALX_RXQ0_RSS_HSTYP_IPV4_EN)
+#define ALX_RXQ0_ASPM_THRESH_MASK 0x3
+#define ALX_RXQ0_ASPM_THRESH_SHIFT 0
+#define ALX_RXQ0_ASPM_THRESH_100M 3
+
+#define ALX_RXQ2 0x15A8
+#define ALX_RXQ2_RXF_XOFF_THRESH_MASK 0xFFF
+#define ALX_RXQ2_RXF_XOFF_THRESH_SHIFT 16
+#define ALX_RXQ2_RXF_XON_THRESH_MASK 0xFFF
+#define ALX_RXQ2_RXF_XON_THRESH_SHIFT 0
+/* Size = tx-packet(1522) + IPG(12) + SOF(8) + 64(Pause) + IPG(12) + SOF(8) +
+ * rx-packet(1522) + delay-of-link(64)
+ * = 3212.
+ */
+#define ALX_RXQ2_RXF_FLOW_CTRL_RSVD 3212
+
+#define ALX_DMA 0x15C0
+#define ALX_DMA_RCHNL_SEL_MASK 0x3
+#define ALX_DMA_RCHNL_SEL_SHIFT 26
+#define ALX_DMA_WDLY_CNT_MASK 0xF
+#define ALX_DMA_WDLY_CNT_SHIFT 16
+#define ALX_DMA_WDLY_CNT_DEF 4
+#define ALX_DMA_RDLY_CNT_MASK 0x1F
+#define ALX_DMA_RDLY_CNT_SHIFT 11
+#define ALX_DMA_RDLY_CNT_DEF 15
+/* bit10: 0:tpd with pri, 1: data */
+#define ALX_DMA_RREQ_PRI_DATA BIT(10)
+#define ALX_DMA_RREQ_BLEN_MASK 0x7
+#define ALX_DMA_RREQ_BLEN_SHIFT 4
+#define ALX_DMA_RORDER_MODE_MASK 0x7
+#define ALX_DMA_RORDER_MODE_SHIFT 0
+#define ALX_DMA_RORDER_MODE_OUT 4
+
+#define ALX_WOL0 0x14A0
+#define ALX_WOL0_PME_LINK BIT(5)
+#define ALX_WOL0_LINK_EN BIT(4)
+#define ALX_WOL0_PME_MAGIC_EN BIT(3)
+#define ALX_WOL0_MAGIC_EN BIT(2)
+
+#define ALX_RFD_PIDX 0x15E0
+
+#define ALX_RFD_CIDX 0x15F8
+
+/* MIB */
+#define ALX_MIB_BASE 0x1700
+#define ALX_MIB_RX_OK (ALX_MIB_BASE + 0)
+#define ALX_MIB_RX_ERRADDR (ALX_MIB_BASE + 92)
+#define ALX_MIB_TX_OK (ALX_MIB_BASE + 96)
+#define ALX_MIB_TX_MCCNT (ALX_MIB_BASE + 192)
+
+#define ALX_RX_STATS_BIN ALX_MIB_RX_OK
+#define ALX_RX_STATS_END ALX_MIB_RX_ERRADDR
+#define ALX_TX_STATS_BIN ALX_MIB_TX_OK
+#define ALX_TX_STATS_END ALX_MIB_TX_MCCNT
+
+#define ALX_ISR 0x1600
+#define ALX_ISR_DIS BIT(31)
+#define ALX_ISR_RX_Q7 BIT(30)
+#define ALX_ISR_RX_Q6 BIT(29)
+#define ALX_ISR_RX_Q5 BIT(28)
+#define ALX_ISR_RX_Q4 BIT(27)
+#define ALX_ISR_PCIE_LNKDOWN BIT(26)
+#define ALX_ISR_RX_Q3 BIT(19)
+#define ALX_ISR_RX_Q2 BIT(18)
+#define ALX_ISR_RX_Q1 BIT(17)
+#define ALX_ISR_RX_Q0 BIT(16)
+#define ALX_ISR_TX_Q0 BIT(15)
+#define ALX_ISR_PHY BIT(12)
+#define ALX_ISR_DMAW BIT(10)
+#define ALX_ISR_DMAR BIT(9)
+#define ALX_ISR_TXF_UR BIT(8)
+#define ALX_ISR_TX_Q3 BIT(7)
+#define ALX_ISR_TX_Q2 BIT(6)
+#define ALX_ISR_TX_Q1 BIT(5)
+#define ALX_ISR_RFD_UR BIT(4)
+#define ALX_ISR_RXF_OV BIT(3)
+#define ALX_ISR_MANU BIT(2)
+#define ALX_ISR_TIMER BIT(1)
+#define ALX_ISR_SMB BIT(0)
+
+#define ALX_IMR 0x1604
+
+/* re-send assert msg if SW no response */
+#define ALX_INT_RETRIG 0x1608
+/* 40ms */
+#define ALX_INT_RETRIG_TO 20000
+
+#define ALX_SMB_TIMER 0x15C4
+
+#define ALX_TINT_TPD_THRSHLD 0x15C8
+
+#define ALX_TINT_TIMER 0x15CC
+
+#define ALX_CLK_GATE 0x1814
+#define ALX_CLK_GATE_RXMAC BIT(5)
+#define ALX_CLK_GATE_TXMAC BIT(4)
+#define ALX_CLK_GATE_RXQ BIT(3)
+#define ALX_CLK_GATE_TXQ BIT(2)
+#define ALX_CLK_GATE_DMAR BIT(1)
+#define ALX_CLK_GATE_DMAW BIT(0)
+#define ALX_CLK_GATE_ALL (ALX_CLK_GATE_RXMAC | \
+ ALX_CLK_GATE_TXMAC | \
+ ALX_CLK_GATE_RXQ | \
+ ALX_CLK_GATE_TXQ | \
+ ALX_CLK_GATE_DMAR | \
+ ALX_CLK_GATE_DMAW)
+
+/* interop between drivers */
+#define ALX_DRV 0x1804
+#define ALX_DRV_PHY_AUTO BIT(28)
+#define ALX_DRV_PHY_1000 BIT(27)
+#define ALX_DRV_PHY_100 BIT(26)
+#define ALX_DRV_PHY_10 BIT(25)
+#define ALX_DRV_PHY_DUPLEX BIT(24)
+/* bit23: adv Pause */
+#define ALX_DRV_PHY_PAUSE BIT(23)
+/* bit22: adv Asym Pause */
+#define ALX_DRV_PHY_MASK 0xFF
+#define ALX_DRV_PHY_SHIFT 21
+#define ALX_DRV_PHY_UNKNOWN 0
+
+/* flag of phy inited */
+#define ALX_PHY_INITED 0x003F
+
+/* reg 1830 ~ 186C for C0+, 16 bit map patterns and wake packet detection */
+#define ALX_WOL_CTRL2 0x1830
+#define ALX_WOL_CTRL2_DATA_STORE BIT(3)
+#define ALX_WOL_CTRL2_PTRN_EVT BIT(2)
+#define ALX_WOL_CTRL2_PME_PTRN_EN BIT(1)
+#define ALX_WOL_CTRL2_PTRN_EN BIT(0)
+
+#define ALX_WOL_CTRL3 0x1834
+#define ALX_WOL_CTRL3_PTRN_ADDR_MASK 0xFFFFF
+#define ALX_WOL_CTRL3_PTRN_ADDR_SHIFT 0
+
+#define ALX_WOL_CTRL4 0x1838
+#define ALX_WOL_CTRL4_PT15_MATCH BIT(31)
+#define ALX_WOL_CTRL4_PT14_MATCH BIT(30)
+#define ALX_WOL_CTRL4_PT13_MATCH BIT(29)
+#define ALX_WOL_CTRL4_PT12_MATCH BIT(28)
+#define ALX_WOL_CTRL4_PT11_MATCH BIT(27)
+#define ALX_WOL_CTRL4_PT10_MATCH BIT(26)
+#define ALX_WOL_CTRL4_PT9_MATCH BIT(25)
+#define ALX_WOL_CTRL4_PT8_MATCH BIT(24)
+#define ALX_WOL_CTRL4_PT7_MATCH BIT(23)
+#define ALX_WOL_CTRL4_PT6_MATCH BIT(22)
+#define ALX_WOL_CTRL4_PT5_MATCH BIT(21)
+#define ALX_WOL_CTRL4_PT4_MATCH BIT(20)
+#define ALX_WOL_CTRL4_PT3_MATCH BIT(19)
+#define ALX_WOL_CTRL4_PT2_MATCH BIT(18)
+#define ALX_WOL_CTRL4_PT1_MATCH BIT(17)
+#define ALX_WOL_CTRL4_PT0_MATCH BIT(16)
+#define ALX_WOL_CTRL4_PT15_EN BIT(15)
+#define ALX_WOL_CTRL4_PT14_EN BIT(14)
+#define ALX_WOL_CTRL4_PT13_EN BIT(13)
+#define ALX_WOL_CTRL4_PT12_EN BIT(12)
+#define ALX_WOL_CTRL4_PT11_EN BIT(11)
+#define ALX_WOL_CTRL4_PT10_EN BIT(10)
+#define ALX_WOL_CTRL4_PT9_EN BIT(9)
+#define ALX_WOL_CTRL4_PT8_EN BIT(8)
+#define ALX_WOL_CTRL4_PT7_EN BIT(7)
+#define ALX_WOL_CTRL4_PT6_EN BIT(6)
+#define ALX_WOL_CTRL4_PT5_EN BIT(5)
+#define ALX_WOL_CTRL4_PT4_EN BIT(4)
+#define ALX_WOL_CTRL4_PT3_EN BIT(3)
+#define ALX_WOL_CTRL4_PT2_EN BIT(2)
+#define ALX_WOL_CTRL4_PT1_EN BIT(1)
+#define ALX_WOL_CTRL4_PT0_EN BIT(0)
+
+#define ALX_WOL_CTRL5 0x183C
+#define ALX_WOL_CTRL5_PT3_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT3_LEN_SHIFT 24
+#define ALX_WOL_CTRL5_PT2_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT2_LEN_SHIFT 16
+#define ALX_WOL_CTRL5_PT1_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT1_LEN_SHIFT 8
+#define ALX_WOL_CTRL5_PT0_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT0_LEN_SHIFT 0
+
+#define ALX_WOL_CTRL6 0x1840
+#define ALX_WOL_CTRL5_PT7_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT7_LEN_SHIFT 24
+#define ALX_WOL_CTRL5_PT6_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT6_LEN_SHIFT 16
+#define ALX_WOL_CTRL5_PT5_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT5_LEN_SHIFT 8
+#define ALX_WOL_CTRL5_PT4_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT4_LEN_SHIFT 0
+
+#define ALX_WOL_CTRL7 0x1844
+#define ALX_WOL_CTRL5_PT11_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT11_LEN_SHIFT 24
+#define ALX_WOL_CTRL5_PT10_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT10_LEN_SHIFT 16
+#define ALX_WOL_CTRL5_PT9_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT9_LEN_SHIFT 8
+#define ALX_WOL_CTRL5_PT8_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT8_LEN_SHIFT 0
+
+#define ALX_WOL_CTRL8 0x1848
+#define ALX_WOL_CTRL5_PT15_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT15_LEN_SHIFT 24
+#define ALX_WOL_CTRL5_PT14_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT14_LEN_SHIFT 16
+#define ALX_WOL_CTRL5_PT13_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT13_LEN_SHIFT 8
+#define ALX_WOL_CTRL5_PT12_LEN_MASK 0xFF
+#define ALX_WOL_CTRL5_PT12_LEN_SHIFT 0
+
+#define ALX_ACER_FIXED_PTN0 0x1850
+#define ALX_ACER_FIXED_PTN0_MASK 0xFFFFFFFF
+#define ALX_ACER_FIXED_PTN0_SHIFT 0
+
+#define ALX_ACER_FIXED_PTN1 0x1854
+#define ALX_ACER_FIXED_PTN1_MASK 0xFFFF
+#define ALX_ACER_FIXED_PTN1_SHIFT 0
+
+#define ALX_ACER_RANDOM_NUM0 0x1858
+#define ALX_ACER_RANDOM_NUM0_MASK 0xFFFFFFFF
+#define ALX_ACER_RANDOM_NUM0_SHIFT 0
+
+#define ALX_ACER_RANDOM_NUM1 0x185C
+#define ALX_ACER_RANDOM_NUM1_MASK 0xFFFFFFFF
+#define ALX_ACER_RANDOM_NUM1_SHIFT 0
+
+#define ALX_ACER_RANDOM_NUM2 0x1860
+#define ALX_ACER_RANDOM_NUM2_MASK 0xFFFFFFFF
+#define ALX_ACER_RANDOM_NUM2_SHIFT 0
+
+#define ALX_ACER_RANDOM_NUM3 0x1864
+#define ALX_ACER_RANDOM_NUM3_MASK 0xFFFFFFFF
+#define ALX_ACER_RANDOM_NUM3_SHIFT 0
+
+#define ALX_ACER_MAGIC 0x1868
+#define ALX_ACER_MAGIC_EN BIT(31)
+#define ALX_ACER_MAGIC_PME_EN BIT(30)
+#define ALX_ACER_MAGIC_MATCH BIT(29)
+#define ALX_ACER_MAGIC_FF_CHECK BIT(10)
+#define ALX_ACER_MAGIC_RAN_LEN_MASK 0x1F
+#define ALX_ACER_MAGIC_RAN_LEN_SHIFT 5
+#define ALX_ACER_MAGIC_FIX_LEN_MASK 0x1F
+#define ALX_ACER_MAGIC_FIX_LEN_SHIFT 0
+
+#define ALX_ACER_TIMER 0x186C
+#define ALX_ACER_TIMER_EN BIT(31)
+#define ALX_ACER_TIMER_PME_EN BIT(30)
+#define ALX_ACER_TIMER_MATCH BIT(29)
+#define ALX_ACER_TIMER_THRES_MASK 0x1FFFF
+#define ALX_ACER_TIMER_THRES_SHIFT 0
+#define ALX_ACER_TIMER_THRES_DEF 1
+
+/* RSS definitions */
+#define ALX_RSS_KEY0 0x14B0
+#define ALX_RSS_KEY1 0x14B4
+#define ALX_RSS_KEY2 0x14B8
+#define ALX_RSS_KEY3 0x14BC
+#define ALX_RSS_KEY4 0x14C0
+#define ALX_RSS_KEY5 0x14C4
+#define ALX_RSS_KEY6 0x14C8
+#define ALX_RSS_KEY7 0x14CC
+#define ALX_RSS_KEY8 0x14D0
+#define ALX_RSS_KEY9 0x14D4
+
+#define ALX_RSS_IDT_TBL0 0x1B00
+
+#define ALX_MSI_MAP_TBL1 0x15D0
+#define ALX_MSI_MAP_TBL1_TXQ1_SHIFT 20
+#define ALX_MSI_MAP_TBL1_TXQ0_SHIFT 16
+#define ALX_MSI_MAP_TBL1_RXQ3_SHIFT 12
+#define ALX_MSI_MAP_TBL1_RXQ2_SHIFT 8
+#define ALX_MSI_MAP_TBL1_RXQ1_SHIFT 4
+#define ALX_MSI_MAP_TBL1_RXQ0_SHIFT 0
+
+#define ALX_MSI_MAP_TBL2 0x15D8
+#define ALX_MSI_MAP_TBL2_TXQ3_SHIFT 20
+#define ALX_MSI_MAP_TBL2_TXQ2_SHIFT 16
+#define ALX_MSI_MAP_TBL2_RXQ7_SHIFT 12
+#define ALX_MSI_MAP_TBL2_RXQ6_SHIFT 8
+#define ALX_MSI_MAP_TBL2_RXQ5_SHIFT 4
+#define ALX_MSI_MAP_TBL2_RXQ4_SHIFT 0
+
+#define ALX_MSI_ID_MAP 0x15D4
+
+#define ALX_MSI_RETRANS_TIMER 0x1920
+/* bit16: 1:line,0:standard */
+#define ALX_MSI_MASK_SEL_LINE BIT(16)
+#define ALX_MSI_RETRANS_TM_MASK 0xFFFF
+#define ALX_MSI_RETRANS_TM_SHIFT 0
+
+/* CR DMA ctrl */
+
+/* TX QoS */
+#define ALX_WRR 0x1938
+#define ALX_WRR_PRI_MASK 0x3
+#define ALX_WRR_PRI_SHIFT 29
+#define ALX_WRR_PRI_RESTRICT_NONE 3
+#define ALX_WRR_PRI3_MASK 0x1F
+#define ALX_WRR_PRI3_SHIFT 24
+#define ALX_WRR_PRI2_MASK 0x1F
+#define ALX_WRR_PRI2_SHIFT 16
+#define ALX_WRR_PRI1_MASK 0x1F
+#define ALX_WRR_PRI1_SHIFT 8
+#define ALX_WRR_PRI0_MASK 0x1F
+#define ALX_WRR_PRI0_SHIFT 0
+
+#define ALX_HQTPD 0x193C
+#define ALX_HQTPD_BURST_EN BIT(31)
+#define ALX_HQTPD_Q3_NUMPREF_MASK 0xF
+#define ALX_HQTPD_Q3_NUMPREF_SHIFT 8
+#define ALX_HQTPD_Q2_NUMPREF_MASK 0xF
+#define ALX_HQTPD_Q2_NUMPREF_SHIFT 4
+#define ALX_HQTPD_Q1_NUMPREF_MASK 0xF
+#define ALX_HQTPD_Q1_NUMPREF_SHIFT 0
+
+#define ALX_MISC 0x19C0
+#define ALX_MISC_PSW_OCP_MASK 0x7
+#define ALX_MISC_PSW_OCP_SHIFT 21
+#define ALX_MISC_PSW_OCP_DEF 0x7
+#define ALX_MISC_ISO_EN BIT(12)
+#define ALX_MISC_INTNLOSC_OPEN BIT(3)
+
+#define ALX_MSIC2 0x19C8
+#define ALX_MSIC2_CALB_START BIT(0)
+
+#define ALX_MISC3 0x19CC
+/* bit1: 1:Software control 25M */
+#define ALX_MISC3_25M_BY_SW BIT(1)
+/* bit0: 25M switch to intnl OSC */
+#define ALX_MISC3_25M_NOTO_INTNL BIT(0)
+
+/* MSIX tbl in memory space */
+#define ALX_MSIX_ENTRY_BASE 0x2000
+
+/********************* PHY regs definition ***************************/
+
+/* PHY Specific Status Register */
+#define ALX_MII_GIGA_PSSR 0x11
+#define ALX_GIGA_PSSR_SPD_DPLX_RESOLVED 0x0800
+#define ALX_GIGA_PSSR_DPLX 0x2000
+#define ALX_GIGA_PSSR_SPEED 0xC000
+#define ALX_GIGA_PSSR_10MBS 0x0000
+#define ALX_GIGA_PSSR_100MBS 0x4000
+#define ALX_GIGA_PSSR_1000MBS 0x8000
+
+/* PHY Interrupt Enable Register */
+#define ALX_MII_IER 0x12
+#define ALX_IER_LINK_UP 0x0400
+#define ALX_IER_LINK_DOWN 0x0800
+
+/* PHY Interrupt Status Register */
+#define ALX_MII_ISR 0x13
+
+#define ALX_MII_DBG_ADDR 0x1D
+#define ALX_MII_DBG_DATA 0x1E
+
+/***************************** debug port *************************************/
+
+#define ALX_MIIDBG_ANACTRL 0x00
+#define ALX_ANACTRL_DEF 0x02EF
+
+#define ALX_MIIDBG_SYSMODCTRL 0x04
+/* en half bias */
+#define ALX_SYSMODCTRL_IECHOADJ_DEF 0xBB8B
+
+#define ALX_MIIDBG_SRDSYSMOD 0x05
+#define ALX_SRDSYSMOD_DEEMP_EN 0x0040
+#define ALX_SRDSYSMOD_DEF 0x2C46
+
+#define ALX_MIIDBG_HIBNEG 0x0B
+#define ALX_HIBNEG_PSHIB_EN 0x8000
+#define ALX_HIBNEG_HIB_PSE 0x1000
+#define ALX_HIBNEG_DEF 0xBC40
+#define ALX_HIBNEG_NOHIB (ALX_HIBNEG_DEF & \
+ ~(ALX_HIBNEG_PSHIB_EN | ALX_HIBNEG_HIB_PSE))
+
+#define ALX_MIIDBG_TST10BTCFG 0x12
+#define ALX_TST10BTCFG_DEF 0x4C04
+
+#define ALX_MIIDBG_AZ_ANADECT 0x15
+#define ALX_AZ_ANADECT_DEF 0x3220
+#define ALX_AZ_ANADECT_LONG 0x3210
+
+#define ALX_MIIDBG_MSE16DB 0x18
+#define ALX_MSE16DB_UP 0x05EA
+#define ALX_MSE16DB_DOWN 0x02EA
+
+#define ALX_MIIDBG_MSE20DB 0x1C
+#define ALX_MSE20DB_TH_MASK 0x7F
+#define ALX_MSE20DB_TH_SHIFT 2
+#define ALX_MSE20DB_TH_DEF 0x2E
+#define ALX_MSE20DB_TH_HI 0x54
+
+#define ALX_MIIDBG_AGC 0x23
+#define ALX_AGC_2_VGA_MASK 0x3FU
+#define ALX_AGC_2_VGA_SHIFT 8
+#define ALX_AGC_LONG1G_LIMT 40
+#define ALX_AGC_LONG100M_LIMT 44
+
+#define ALX_MIIDBG_LEGCYPS 0x29
+#define ALX_LEGCYPS_EN 0x8000
+#define ALX_LEGCYPS_DEF 0x129D
+
+#define ALX_MIIDBG_TST100BTCFG 0x36
+#define ALX_TST100BTCFG_DEF 0xE12C
+
+#define ALX_MIIDBG_GREENCFG 0x3B
+#define ALX_GREENCFG_DEF 0x7078
+
+#define ALX_MIIDBG_GREENCFG2 0x3D
+#define ALX_GREENCFG2_BP_GREEN 0x8000
+#define ALX_GREENCFG2_GATE_DFSE_EN 0x0080
+
+/******* dev 3 *********/
+#define ALX_MIIEXT_PCS 3
+
+#define ALX_MIIEXT_CLDCTRL3 0x8003
+#define ALX_CLDCTRL3_BP_CABLE1TH_DET_GT 0x8000
+
+#define ALX_MIIEXT_CLDCTRL5 0x8005
+#define ALX_CLDCTRL5_BP_VD_HLFBIAS 0x4000
+
+#define ALX_MIIEXT_CLDCTRL6 0x8006
+#define ALX_CLDCTRL6_CAB_LEN_MASK 0xFF
+#define ALX_CLDCTRL6_CAB_LEN_SHIFT 0
+#define ALX_CLDCTRL6_CAB_LEN_SHORT1G 116
+#define ALX_CLDCTRL6_CAB_LEN_SHORT100M 152
+
+#define ALX_MIIEXT_VDRVBIAS 0x8062
+#define ALX_VDRVBIAS_DEF 0x3
+
+/********* dev 7 **********/
+#define ALX_MIIEXT_ANEG 7
+
+#define ALX_MIIEXT_LOCAL_EEEADV 0x3C
+#define ALX_LOCAL_EEEADV_1000BT 0x0004
+#define ALX_LOCAL_EEEADV_100BT 0x0002
+
+#define ALX_MIIEXT_AFE 0x801A
+#define ALX_AFE_10BT_100M_TH 0x0040
+
+#define ALX_MIIEXT_S3DIG10 0x8023
+/* bit0: 1:bypass 10BT rx fifo, 0:original 10BT rx */
+#define ALX_MIIEXT_S3DIG10_SL 0x0001
+#define ALX_MIIEXT_S3DIG10_DEF 0
+
+#define ALX_MIIEXT_NLP78 0x8027
+#define ALX_MIIEXT_NLP78_120M_DEF 0x8A05
+
+#endif
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 0ba9007..786a874 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -2755,27 +2755,4 @@ static struct pci_driver atl1c_driver = {
.driver.pm = &atl1c_pm_ops,
};
-/**
- * atl1c_init_module - Driver Registration Routine
- *
- * atl1c_init_module is the first routine called when the driver is
- * loaded. All it does is register with the PCI subsystem.
- */
-static int __init atl1c_init_module(void)
-{
- return pci_register_driver(&atl1c_driver);
-}
-
-/**
- * atl1c_exit_module - Driver Exit Cleanup Routine
- *
- * atl1c_exit_module is called just before the driver is removed
- * from memory.
- */
-static void __exit atl1c_exit_module(void)
-{
- pci_unregister_driver(&atl1c_driver);
-}
-
-module_init(atl1c_init_module);
-module_exit(atl1c_exit_module);
+module_pci_driver(atl1c_driver);
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index 0688bb8..895f537 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -2489,27 +2489,4 @@ static struct pci_driver atl1e_driver = {
.err_handler = &atl1e_err_handler
};
-/**
- * atl1e_init_module - Driver Registration Routine
- *
- * atl1e_init_module is the first routine called when the driver is
- * loaded. All it does is register with the PCI subsystem.
- */
-static int __init atl1e_init_module(void)
-{
- return pci_register_driver(&atl1e_driver);
-}
-
-/**
- * atl1e_exit_module - Driver Exit Cleanup Routine
- *
- * atl1e_exit_module is called just before the driver is removed
- * from memory.
- */
-static void __exit atl1e_exit_module(void)
-{
- pci_unregister_driver(&atl1e_driver);
-}
-
-module_init(atl1e_init_module);
-module_exit(atl1e_exit_module);
+module_pci_driver(atl1e_driver);
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index fa0915f..538211d 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -3145,31 +3145,6 @@ static struct pci_driver atl1_driver = {
.driver.pm = &atl1_pm_ops,
};
-/**
- * atl1_exit_module - Driver Exit Cleanup Routine
- *
- * atl1_exit_module is called just before the driver is removed
- * from memory.
- */
-static void __exit atl1_exit_module(void)
-{
- pci_unregister_driver(&atl1_driver);
-}
-
-/**
- * atl1_init_module - Driver Registration Routine
- *
- * atl1_init_module is the first routine called when the driver is
- * loaded. All it does is register with the PCI subsystem.
- */
-static int __init atl1_init_module(void)
-{
- return pci_register_driver(&atl1_driver);
-}
-
-module_init(atl1_init_module);
-module_exit(atl1_exit_module);
-
struct atl1_stats {
char stat_string[ETH_GSTRING_LEN];
int sizeof_stat;
@@ -3705,3 +3680,5 @@ static const struct ethtool_ops atl1_ethtool_ops = {
.get_ethtool_stats = atl1_get_ethtool_stats,
.get_sset_count = atl1_get_sset_count,
};
+
+module_pci_driver(atl1_driver);
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 3e69b3f..1d680ba 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -22,7 +22,6 @@ config B44
tristate "Broadcom 440x/47xx ethernet support"
depends on SSB_POSSIBLE && HAS_DMA
select SSB
- select NET_CORE
select MII
---help---
If you have a network (Ethernet) controller of this type, say Y
@@ -54,7 +53,6 @@ config B44_PCI
config BCM63XX_ENET
tristate "Broadcom 63xx internal mac support"
depends on BCM63XX
- select NET_CORE
select MII
select PHYLIB
help
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 0b3e23e..b1bcd4b 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -41,8 +41,8 @@ static int copybreak __read_mostly = 128;
module_param(copybreak, int, 0);
MODULE_PARM_DESC(copybreak, "Receive copy threshold");
-/* io memory shared between all devices */
-static void __iomem *bcm_enet_shared_base;
+/* io registers memory shared between all devices */
+static void __iomem *bcm_enet_shared_base[3];
/*
* io helpers to access mac registers
@@ -59,17 +59,76 @@ static inline void enet_writel(struct bcm_enet_priv *priv,
}
/*
- * io helpers to access shared registers
+ * io helpers to access switch registers
*/
+static inline u32 enetsw_readl(struct bcm_enet_priv *priv, u32 off)
+{
+ return bcm_readl(priv->base + off);
+}
+
+static inline void enetsw_writel(struct bcm_enet_priv *priv,
+ u32 val, u32 off)
+{
+ bcm_writel(val, priv->base + off);
+}
+
+static inline u16 enetsw_readw(struct bcm_enet_priv *priv, u32 off)
+{
+ return bcm_readw(priv->base + off);
+}
+
+static inline void enetsw_writew(struct bcm_enet_priv *priv,
+ u16 val, u32 off)
+{
+ bcm_writew(val, priv->base + off);
+}
+
+static inline u8 enetsw_readb(struct bcm_enet_priv *priv, u32 off)
+{
+ return bcm_readb(priv->base + off);
+}
+
+static inline void enetsw_writeb(struct bcm_enet_priv *priv,
+ u8 val, u32 off)
+{
+ bcm_writeb(val, priv->base + off);
+}
+
+
+/* io helpers to access shared registers */
static inline u32 enet_dma_readl(struct bcm_enet_priv *priv, u32 off)
{
- return bcm_readl(bcm_enet_shared_base + off);
+ return bcm_readl(bcm_enet_shared_base[0] + off);
}
static inline void enet_dma_writel(struct bcm_enet_priv *priv,
u32 val, u32 off)
{
- bcm_writel(val, bcm_enet_shared_base + off);
+ bcm_writel(val, bcm_enet_shared_base[0] + off);
+}
+
+static inline u32 enet_dmac_readl(struct bcm_enet_priv *priv, u32 off, int chan)
+{
+ return bcm_readl(bcm_enet_shared_base[1] +
+ bcm63xx_enetdmacreg(off) + chan * priv->dma_chan_width);
+}
+
+static inline void enet_dmac_writel(struct bcm_enet_priv *priv,
+ u32 val, u32 off, int chan)
+{
+ bcm_writel(val, bcm_enet_shared_base[1] +
+ bcm63xx_enetdmacreg(off) + chan * priv->dma_chan_width);
+}
+
+static inline u32 enet_dmas_readl(struct bcm_enet_priv *priv, u32 off, int chan)
+{
+ return bcm_readl(bcm_enet_shared_base[2] + off + chan * priv->dma_chan_width);
+}
+
+static inline void enet_dmas_writel(struct bcm_enet_priv *priv,
+ u32 val, u32 off, int chan)
+{
+ bcm_writel(val, bcm_enet_shared_base[2] + off + chan * priv->dma_chan_width);
}
/*
@@ -196,7 +255,6 @@ static int bcm_enet_refill_rx(struct net_device *dev)
if (!skb)
break;
priv->rx_skb[desc_idx] = skb;
-
p = dma_map_single(&priv->pdev->dev, skb->data,
priv->rx_skb_size,
DMA_FROM_DEVICE);
@@ -206,7 +264,7 @@ static int bcm_enet_refill_rx(struct net_device *dev)
len_stat = priv->rx_skb_size << DMADESC_LENGTH_SHIFT;
len_stat |= DMADESC_OWNER_MASK;
if (priv->rx_dirty_desc == priv->rx_ring_size - 1) {
- len_stat |= DMADESC_WRAP_MASK;
+ len_stat |= (DMADESC_WRAP_MASK >> priv->dma_desc_shift);
priv->rx_dirty_desc = 0;
} else {
priv->rx_dirty_desc++;
@@ -217,7 +275,10 @@ static int bcm_enet_refill_rx(struct net_device *dev)
priv->rx_desc_count++;
/* tell dma engine we allocated one buffer */
- enet_dma_writel(priv, 1, ENETDMA_BUFALLOC_REG(priv->rx_chan));
+ if (priv->dma_has_sram)
+ enet_dma_writel(priv, 1, ENETDMA_BUFALLOC_REG(priv->rx_chan));
+ else
+ enet_dmac_writel(priv, 1, ENETDMAC_BUFALLOC, priv->rx_chan);
}
/* If rx ring is still empty, set a timer to try allocating
@@ -293,13 +354,15 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
/* if the packet does not have start of packet _and_
* end of packet flag set, then just recycle it */
- if ((len_stat & DMADESC_ESOP_MASK) != DMADESC_ESOP_MASK) {
+ if ((len_stat & (DMADESC_ESOP_MASK >> priv->dma_desc_shift)) !=
+ (DMADESC_ESOP_MASK >> priv->dma_desc_shift)) {
dev->stats.rx_dropped++;
continue;
}
/* recycle packet if it's marked as bad */
- if (unlikely(len_stat & DMADESC_ERR_MASK)) {
+ if (!priv->enet_is_sw &&
+ unlikely(len_stat & DMADESC_ERR_MASK)) {
dev->stats.rx_errors++;
if (len_stat & DMADESC_OVSIZE_MASK)
@@ -353,8 +416,8 @@ static int bcm_enet_receive_queue(struct net_device *dev, int budget)
bcm_enet_refill_rx(dev);
/* kick rx dma */
- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK,
- ENETDMA_CHANCFG_REG(priv->rx_chan));
+ enet_dmac_writel(priv, priv->dma_chan_en_mask,
+ ENETDMAC_CHANCFG, priv->rx_chan);
}
return processed;
@@ -429,10 +492,10 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
dev = priv->net_dev;
/* ack interrupts */
- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
- ENETDMA_IR_REG(priv->rx_chan));
- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
- ENETDMA_IR_REG(priv->tx_chan));
+ enet_dmac_writel(priv, priv->dma_chan_int_mask,
+ ENETDMAC_IR, priv->rx_chan);
+ enet_dmac_writel(priv, priv->dma_chan_int_mask,
+ ENETDMAC_IR, priv->tx_chan);
/* reclaim sent skb */
tx_work_done = bcm_enet_tx_reclaim(dev, 0);
@@ -451,10 +514,10 @@ static int bcm_enet_poll(struct napi_struct *napi, int budget)
napi_complete(napi);
/* restore rx/tx interrupt */
- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
- ENETDMA_IRMASK_REG(priv->rx_chan));
- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
- ENETDMA_IRMASK_REG(priv->tx_chan));
+ enet_dmac_writel(priv, priv->dma_chan_int_mask,
+ ENETDMAC_IRMASK, priv->rx_chan);
+ enet_dmac_writel(priv, priv->dma_chan_int_mask,
+ ENETDMAC_IRMASK, priv->tx_chan);
return rx_work_done;
}
@@ -497,8 +560,8 @@ static irqreturn_t bcm_enet_isr_dma(int irq, void *dev_id)
priv = netdev_priv(dev);
/* mask rx/tx interrupts */
- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan));
- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan));
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan);
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan);
napi_schedule(&priv->napi);
@@ -530,6 +593,26 @@ static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto out_unlock;
}
+ /* pad small packets sent on a switch device */
+ if (priv->enet_is_sw && skb->len < 64) {
+ int needed = 64 - skb->len;
+ char *data;
+
+ if (unlikely(skb_tailroom(skb) < needed)) {
+ struct sk_buff *nskb;
+
+ nskb = skb_copy_expand(skb, 0, needed, GFP_ATOMIC);
+ if (!nskb) {
+ ret = NETDEV_TX_BUSY;
+ goto out_unlock;
+ }
+ dev_kfree_skb(skb);
+ skb = nskb;
+ }
+ data = skb_put(skb, needed);
+ memset(data, 0, needed);
+ }
+
/* point to the next available desc */
desc = &priv->tx_desc_cpu[priv->tx_curr_desc];
priv->tx_skb[priv->tx_curr_desc] = skb;
@@ -539,14 +622,14 @@ static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
DMA_TO_DEVICE);
len_stat = (skb->len << DMADESC_LENGTH_SHIFT) & DMADESC_LENGTH_MASK;
- len_stat |= DMADESC_ESOP_MASK |
+ len_stat |= (DMADESC_ESOP_MASK >> priv->dma_desc_shift) |
DMADESC_APPEND_CRC |
DMADESC_OWNER_MASK;
priv->tx_curr_desc++;
if (priv->tx_curr_desc == priv->tx_ring_size) {
priv->tx_curr_desc = 0;
- len_stat |= DMADESC_WRAP_MASK;
+ len_stat |= (DMADESC_WRAP_MASK >> priv->dma_desc_shift);
}
priv->tx_desc_count--;
@@ -557,8 +640,8 @@ static int bcm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
wmb();
/* kick tx dma */
- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK,
- ENETDMA_CHANCFG_REG(priv->tx_chan));
+ enet_dmac_writel(priv, priv->dma_chan_en_mask,
+ ENETDMAC_CHANCFG, priv->tx_chan);
/* stop queue if no more desc available */
if (!priv->tx_desc_count)
@@ -686,6 +769,9 @@ static void bcm_enet_set_flow(struct bcm_enet_priv *priv, int rx_en, int tx_en)
val &= ~ENET_RXCFG_ENFLOW_MASK;
enet_writel(priv, val, ENET_RXCFG_REG);
+ if (!priv->dma_has_sram)
+ return;
+
/* tx flow control (pause frame generation) */
val = enet_dma_readl(priv, ENETDMA_CFG_REG);
if (tx_en)
@@ -833,8 +919,8 @@ static int bcm_enet_open(struct net_device *dev)
/* mask all interrupts and request them */
enet_writel(priv, 0, ENET_IRMASK_REG);
- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan));
- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan));
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan);
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan);
ret = request_irq(dev->irq, bcm_enet_isr_mac, 0, dev->name, dev);
if (ret)
@@ -909,8 +995,12 @@ static int bcm_enet_open(struct net_device *dev)
priv->rx_curr_desc = 0;
/* initialize flow control buffer allocation */
- enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0,
- ENETDMA_BUFALLOC_REG(priv->rx_chan));
+ if (priv->dma_has_sram)
+ enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0,
+ ENETDMA_BUFALLOC_REG(priv->rx_chan));
+ else
+ enet_dmac_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0,
+ ENETDMAC_BUFALLOC, priv->rx_chan);
if (bcm_enet_refill_rx(dev)) {
dev_err(kdev, "cannot allocate rx skb queue\n");
@@ -919,37 +1009,55 @@ static int bcm_enet_open(struct net_device *dev)
}
/* write rx & tx ring addresses */
- enet_dma_writel(priv, priv->rx_desc_dma,
- ENETDMA_RSTART_REG(priv->rx_chan));
- enet_dma_writel(priv, priv->tx_desc_dma,
- ENETDMA_RSTART_REG(priv->tx_chan));
+ if (priv->dma_has_sram) {
+ enet_dmas_writel(priv, priv->rx_desc_dma,
+ ENETDMAS_RSTART_REG, priv->rx_chan);
+ enet_dmas_writel(priv, priv->tx_desc_dma,
+ ENETDMAS_RSTART_REG, priv->tx_chan);
+ } else {
+ enet_dmac_writel(priv, priv->rx_desc_dma,
+ ENETDMAC_RSTART, priv->rx_chan);
+ enet_dmac_writel(priv, priv->tx_desc_dma,
+ ENETDMAC_RSTART, priv->tx_chan);
+ }
/* clear remaining state ram for rx & tx channel */
- enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->rx_chan));
- enet_dma_writel(priv, 0, ENETDMA_SRAM2_REG(priv->tx_chan));
- enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->rx_chan));
- enet_dma_writel(priv, 0, ENETDMA_SRAM3_REG(priv->tx_chan));
- enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->rx_chan));
- enet_dma_writel(priv, 0, ENETDMA_SRAM4_REG(priv->tx_chan));
+ if (priv->dma_has_sram) {
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG, priv->rx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG, priv->tx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG, priv->rx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG, priv->tx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG, priv->rx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG, priv->tx_chan);
+ } else {
+ enet_dmac_writel(priv, 0, ENETDMAC_FC, priv->rx_chan);
+ enet_dmac_writel(priv, 0, ENETDMAC_FC, priv->tx_chan);
+ }
/* set max rx/tx length */
enet_writel(priv, priv->hw_mtu, ENET_RXMAXLEN_REG);
enet_writel(priv, priv->hw_mtu, ENET_TXMAXLEN_REG);
/* set dma maximum burst len */
- enet_dma_writel(priv, BCMENET_DMA_MAXBURST,
- ENETDMA_MAXBURST_REG(priv->rx_chan));
- enet_dma_writel(priv, BCMENET_DMA_MAXBURST,
- ENETDMA_MAXBURST_REG(priv->tx_chan));
+ enet_dmac_writel(priv, priv->dma_maxburst,
+ ENETDMAC_MAXBURST, priv->rx_chan);
+ enet_dmac_writel(priv, priv->dma_maxburst,
+ ENETDMAC_MAXBURST, priv->tx_chan);
/* set correct transmit fifo watermark */
enet_writel(priv, BCMENET_TX_FIFO_TRESH, ENET_TXWMARK_REG);
/* set flow control low/high threshold to 1/3 / 2/3 */
- val = priv->rx_ring_size / 3;
- enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan));
- val = (priv->rx_ring_size * 2) / 3;
- enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan));
+ if (priv->dma_has_sram) {
+ val = priv->rx_ring_size / 3;
+ enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan));
+ val = (priv->rx_ring_size * 2) / 3;
+ enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan));
+ } else {
+ enet_dmac_writel(priv, 5, ENETDMAC_FC, priv->rx_chan);
+ enet_dmac_writel(priv, priv->rx_ring_size, ENETDMAC_LEN, priv->rx_chan);
+ enet_dmac_writel(priv, priv->tx_ring_size, ENETDMAC_LEN, priv->tx_chan);
+ }
/* all set, enable mac and interrupts, start dma engine and
* kick rx dma channel */
@@ -958,26 +1066,26 @@ static int bcm_enet_open(struct net_device *dev)
val |= ENET_CTL_ENABLE_MASK;
enet_writel(priv, val, ENET_CTL_REG);
enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
- enet_dma_writel(priv, ENETDMA_CHANCFG_EN_MASK,
- ENETDMA_CHANCFG_REG(priv->rx_chan));
+ enet_dmac_writel(priv, priv->dma_chan_en_mask,
+ ENETDMAC_CHANCFG, priv->rx_chan);
/* watch "mib counters about to overflow" interrupt */
enet_writel(priv, ENET_IR_MIB, ENET_IR_REG);
enet_writel(priv, ENET_IR_MIB, ENET_IRMASK_REG);
/* watch "packet transferred" interrupt in rx and tx */
- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
- ENETDMA_IR_REG(priv->rx_chan));
- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
- ENETDMA_IR_REG(priv->tx_chan));
+ enet_dmac_writel(priv, priv->dma_chan_int_mask,
+ ENETDMAC_IR, priv->rx_chan);
+ enet_dmac_writel(priv, priv->dma_chan_int_mask,
+ ENETDMAC_IR, priv->tx_chan);
/* make sure we enable napi before rx interrupt */
napi_enable(&priv->napi);
- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
- ENETDMA_IRMASK_REG(priv->rx_chan));
- enet_dma_writel(priv, ENETDMA_IR_PKTDONE_MASK,
- ENETDMA_IRMASK_REG(priv->tx_chan));
+ enet_dmac_writel(priv, priv->dma_chan_int_mask,
+ ENETDMAC_IRMASK, priv->rx_chan);
+ enet_dmac_writel(priv, priv->dma_chan_int_mask,
+ ENETDMAC_IRMASK, priv->tx_chan);
if (priv->has_phy)
phy_start(priv->phydev);
@@ -1057,14 +1165,14 @@ static void bcm_enet_disable_dma(struct bcm_enet_priv *priv, int chan)
{
int limit;
- enet_dma_writel(priv, 0, ENETDMA_CHANCFG_REG(chan));
+ enet_dmac_writel(priv, 0, ENETDMAC_CHANCFG, chan);
limit = 1000;
do {
u32 val;
- val = enet_dma_readl(priv, ENETDMA_CHANCFG_REG(chan));
- if (!(val & ENETDMA_CHANCFG_EN_MASK))
+ val = enet_dmac_readl(priv, ENETDMAC_CHANCFG, chan);
+ if (!(val & ENETDMAC_CHANCFG_EN_MASK))
break;
udelay(1);
} while (limit--);
@@ -1090,8 +1198,8 @@ static int bcm_enet_stop(struct net_device *dev)
/* mask all interrupts */
enet_writel(priv, 0, ENET_IRMASK_REG);
- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->rx_chan));
- enet_dma_writel(priv, 0, ENETDMA_IRMASK_REG(priv->tx_chan));
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan);
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan);
/* make sure no mib update is scheduled */
cancel_work_sync(&priv->mib_update_task);
@@ -1328,6 +1436,20 @@ static void bcm_enet_get_ethtool_stats(struct net_device *netdev,
mutex_unlock(&priv->mib_update_lock);
}
+static int bcm_enet_nway_reset(struct net_device *dev)
+{
+ struct bcm_enet_priv *priv;
+
+ priv = netdev_priv(dev);
+ if (priv->has_phy) {
+ if (!priv->phydev)
+ return -ENODEV;
+ return genphy_restart_aneg(priv->phydev);
+ }
+
+ return -EOPNOTSUPP;
+}
+
static int bcm_enet_get_settings(struct net_device *dev,
struct ethtool_cmd *cmd)
{
@@ -1470,6 +1592,7 @@ static const struct ethtool_ops bcm_enet_ethtool_ops = {
.get_strings = bcm_enet_get_strings,
.get_sset_count = bcm_enet_get_sset_count,
.get_ethtool_stats = bcm_enet_get_ethtool_stats,
+ .nway_reset = bcm_enet_nway_reset,
.get_settings = bcm_enet_get_settings,
.set_settings = bcm_enet_set_settings,
.get_drvinfo = bcm_enet_get_drvinfo,
@@ -1530,7 +1653,7 @@ static int compute_hw_mtu(struct bcm_enet_priv *priv, int mtu)
* it's appended
*/
priv->rx_skb_size = ALIGN(actual_mtu + ETH_FCS_LEN,
- BCMENET_DMA_MAXBURST * 4);
+ priv->dma_maxburst * 4);
return 0;
}
@@ -1621,7 +1744,7 @@ static int bcm_enet_probe(struct platform_device *pdev)
/* stop if shared driver failed, assume driver->probe will be
* called in the same order we register devices (correct ?) */
- if (!bcm_enet_shared_base)
+ if (!bcm_enet_shared_base[0])
return -ENODEV;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1637,6 +1760,9 @@ static int bcm_enet_probe(struct platform_device *pdev)
return -ENOMEM;
priv = netdev_priv(dev);
+ priv->enet_is_sw = false;
+ priv->dma_maxburst = BCMENET_DMA_MAXBURST;
+
ret = compute_hw_mtu(priv, dev->mtu);
if (ret)
goto out;
@@ -1687,6 +1813,11 @@ static int bcm_enet_probe(struct platform_device *pdev)
priv->pause_tx = pd->pause_tx;
priv->force_duplex_full = pd->force_duplex_full;
priv->force_speed_100 = pd->force_speed_100;
+ priv->dma_chan_en_mask = pd->dma_chan_en_mask;
+ priv->dma_chan_int_mask = pd->dma_chan_int_mask;
+ priv->dma_chan_width = pd->dma_chan_width;
+ priv->dma_has_sram = pd->dma_has_sram;
+ priv->dma_desc_shift = pd->dma_desc_shift;
}
if (priv->mac_id == 0 && priv->has_phy && !priv->use_external_mii) {
@@ -1847,7 +1978,6 @@ static int bcm_enet_remove(struct platform_device *pdev)
clk_disable_unprepare(priv->mac_clk);
clk_put(priv->mac_clk);
- platform_set_drvdata(pdev, NULL);
free_netdev(dev);
return 0;
}
@@ -1862,19 +1992,881 @@ struct platform_driver bcm63xx_enet_driver = {
};
/*
- * reserve & remap memory space shared between all macs
+ * switch mii access callbacks
*/
-static int bcm_enet_shared_probe(struct platform_device *pdev)
+static int bcmenet_sw_mdio_read(struct bcm_enet_priv *priv,
+ int ext, int phy_id, int location)
{
- struct resource *res;
+ u32 reg;
+ int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
+ spin_lock_bh(&priv->enetsw_mdio_lock);
+ enetsw_writel(priv, 0, ENETSW_MDIOC_REG);
+
+ reg = ENETSW_MDIOC_RD_MASK |
+ (phy_id << ENETSW_MDIOC_PHYID_SHIFT) |
+ (location << ENETSW_MDIOC_REG_SHIFT);
+
+ if (ext)
+ reg |= ENETSW_MDIOC_EXT_MASK;
+
+ enetsw_writel(priv, reg, ENETSW_MDIOC_REG);
+ udelay(50);
+ ret = enetsw_readw(priv, ENETSW_MDIOD_REG);
+ spin_unlock_bh(&priv->enetsw_mdio_lock);
+ return ret;
+}
+
+static void bcmenet_sw_mdio_write(struct bcm_enet_priv *priv,
+ int ext, int phy_id, int location,
+ uint16_t data)
+{
+ u32 reg;
+
+ spin_lock_bh(&priv->enetsw_mdio_lock);
+ enetsw_writel(priv, 0, ENETSW_MDIOC_REG);
+
+ reg = ENETSW_MDIOC_WR_MASK |
+ (phy_id << ENETSW_MDIOC_PHYID_SHIFT) |
+ (location << ENETSW_MDIOC_REG_SHIFT);
+
+ if (ext)
+ reg |= ENETSW_MDIOC_EXT_MASK;
+
+ reg |= data;
+
+ enetsw_writel(priv, reg, ENETSW_MDIOC_REG);
+ udelay(50);
+ spin_unlock_bh(&priv->enetsw_mdio_lock);
+}
+
+static inline int bcm_enet_port_is_rgmii(int portid)
+{
+ return portid >= ENETSW_RGMII_PORT0;
+}
+
+/*
+ * enet sw PHY polling
+ */
+static void swphy_poll_timer(unsigned long data)
+{
+ struct bcm_enet_priv *priv = (struct bcm_enet_priv *)data;
+ unsigned int i;
+
+ for (i = 0; i < priv->num_ports; i++) {
+ struct bcm63xx_enetsw_port *port;
+ int val, j, up, advertise, lpa, lpa2, speed, duplex, media;
+ int external_phy = bcm_enet_port_is_rgmii(i);
+ u8 override;
+
+ port = &priv->used_ports[i];
+ if (!port->used)
+ continue;
+
+ if (port->bypass_link)
+ continue;
+
+ /* dummy read to clear */
+ for (j = 0; j < 2; j++)
+ val = bcmenet_sw_mdio_read(priv, external_phy,
+ port->phy_id, MII_BMSR);
+
+ if (val == 0xffff)
+ continue;
+
+ up = (val & BMSR_LSTATUS) ? 1 : 0;
+ if (!(up ^ priv->sw_port_link[i]))
+ continue;
+
+ priv->sw_port_link[i] = up;
+
+ /* link changed */
+ if (!up) {
+ dev_info(&priv->pdev->dev, "link DOWN on %s\n",
+ port->name);
+ enetsw_writeb(priv, ENETSW_PORTOV_ENABLE_MASK,
+ ENETSW_PORTOV_REG(i));
+ enetsw_writeb(priv, ENETSW_PTCTRL_RXDIS_MASK |
+ ENETSW_PTCTRL_TXDIS_MASK,
+ ENETSW_PTCTRL_REG(i));
+ continue;
+ }
+
+ advertise = bcmenet_sw_mdio_read(priv, external_phy,
+ port->phy_id, MII_ADVERTISE);
+
+ lpa = bcmenet_sw_mdio_read(priv, external_phy, port->phy_id,
+ MII_LPA);
+
+ lpa2 = bcmenet_sw_mdio_read(priv, external_phy, port->phy_id,
+ MII_STAT1000);
+
+ /* figure out media and duplex from advertise and LPA values */
+ media = mii_nway_result(lpa & advertise);
+ duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+ if (lpa2 & LPA_1000FULL)
+ duplex = 1;
+
+ if (lpa2 & (LPA_1000FULL | LPA_1000HALF))
+ speed = 1000;
+ else {
+ if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF))
+ speed = 100;
+ else
+ speed = 10;
+ }
+
+ dev_info(&priv->pdev->dev,
+ "link UP on %s, %dMbps, %s-duplex\n",
+ port->name, speed, duplex ? "full" : "half");
+
+ override = ENETSW_PORTOV_ENABLE_MASK |
+ ENETSW_PORTOV_LINKUP_MASK;
+
+ if (speed == 1000)
+ override |= ENETSW_IMPOV_1000_MASK;
+ else if (speed == 100)
+ override |= ENETSW_IMPOV_100_MASK;
+ if (duplex)
+ override |= ENETSW_IMPOV_FDX_MASK;
+
+ enetsw_writeb(priv, override, ENETSW_PORTOV_REG(i));
+ enetsw_writeb(priv, 0, ENETSW_PTCTRL_REG(i));
+ }
+
+ priv->swphy_poll.expires = jiffies + HZ;
+ add_timer(&priv->swphy_poll);
+}
+
+/*
+ * open callback, allocate dma rings & buffers and start rx operation
+ */
+static int bcm_enetsw_open(struct net_device *dev)
+{
+ struct bcm_enet_priv *priv;
+ struct device *kdev;
+ int i, ret;
+ unsigned int size;
+ void *p;
+ u32 val;
+
+ priv = netdev_priv(dev);
+ kdev = &priv->pdev->dev;
+
+ /* mask all interrupts and request them */
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan);
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan);
+
+ ret = request_irq(priv->irq_rx, bcm_enet_isr_dma,
+ IRQF_DISABLED, dev->name, dev);
+ if (ret)
+ goto out_freeirq;
+
+ if (priv->irq_tx != -1) {
+ ret = request_irq(priv->irq_tx, bcm_enet_isr_dma,
+ IRQF_DISABLED, dev->name, dev);
+ if (ret)
+ goto out_freeirq_rx;
+ }
+
+ /* allocate rx dma ring */
+ size = priv->rx_ring_size * sizeof(struct bcm_enet_desc);
+ p = dma_alloc_coherent(kdev, size, &priv->rx_desc_dma, GFP_KERNEL);
+ if (!p) {
+ dev_err(kdev, "cannot allocate rx ring %u\n", size);
+ ret = -ENOMEM;
+ goto out_freeirq_tx;
+ }
+
+ memset(p, 0, size);
+ priv->rx_desc_alloc_size = size;
+ priv->rx_desc_cpu = p;
+
+ /* allocate tx dma ring */
+ size = priv->tx_ring_size * sizeof(struct bcm_enet_desc);
+ p = dma_alloc_coherent(kdev, size, &priv->tx_desc_dma, GFP_KERNEL);
+ if (!p) {
+ dev_err(kdev, "cannot allocate tx ring\n");
+ ret = -ENOMEM;
+ goto out_free_rx_ring;
+ }
+
+ memset(p, 0, size);
+ priv->tx_desc_alloc_size = size;
+ priv->tx_desc_cpu = p;
+
+ priv->tx_skb = kzalloc(sizeof(struct sk_buff *) * priv->tx_ring_size,
+ GFP_KERNEL);
+ if (!priv->tx_skb) {
+ dev_err(kdev, "cannot allocate rx skb queue\n");
+ ret = -ENOMEM;
+ goto out_free_tx_ring;
+ }
+
+ priv->tx_desc_count = priv->tx_ring_size;
+ priv->tx_dirty_desc = 0;
+ priv->tx_curr_desc = 0;
+ spin_lock_init(&priv->tx_lock);
+
+ /* init & fill rx ring with skbs */
+ priv->rx_skb = kzalloc(sizeof(struct sk_buff *) * priv->rx_ring_size,
+ GFP_KERNEL);
+ if (!priv->rx_skb) {
+ dev_err(kdev, "cannot allocate rx skb queue\n");
+ ret = -ENOMEM;
+ goto out_free_tx_skb;
+ }
+
+ priv->rx_desc_count = 0;
+ priv->rx_dirty_desc = 0;
+ priv->rx_curr_desc = 0;
+
+ /* disable all ports */
+ for (i = 0; i < priv->num_ports; i++) {
+ enetsw_writeb(priv, ENETSW_PORTOV_ENABLE_MASK,
+ ENETSW_PORTOV_REG(i));
+ enetsw_writeb(priv, ENETSW_PTCTRL_RXDIS_MASK |
+ ENETSW_PTCTRL_TXDIS_MASK,
+ ENETSW_PTCTRL_REG(i));
+
+ priv->sw_port_link[i] = 0;
+ }
+
+ /* reset mib */
+ val = enetsw_readb(priv, ENETSW_GMCR_REG);
+ val |= ENETSW_GMCR_RST_MIB_MASK;
+ enetsw_writeb(priv, val, ENETSW_GMCR_REG);
+ mdelay(1);
+ val &= ~ENETSW_GMCR_RST_MIB_MASK;
+ enetsw_writeb(priv, val, ENETSW_GMCR_REG);
+ mdelay(1);
+
+ /* force CPU port state */
+ val = enetsw_readb(priv, ENETSW_IMPOV_REG);
+ val |= ENETSW_IMPOV_FORCE_MASK | ENETSW_IMPOV_LINKUP_MASK;
+ enetsw_writeb(priv, val, ENETSW_IMPOV_REG);
+
+ /* enable switch forward engine */
+ val = enetsw_readb(priv, ENETSW_SWMODE_REG);
+ val |= ENETSW_SWMODE_FWD_EN_MASK;
+ enetsw_writeb(priv, val, ENETSW_SWMODE_REG);
+
+ /* enable jumbo on all ports */
+ enetsw_writel(priv, 0x1ff, ENETSW_JMBCTL_PORT_REG);
+ enetsw_writew(priv, 9728, ENETSW_JMBCTL_MAXSIZE_REG);
+
+ /* initialize flow control buffer allocation */
+ enet_dma_writel(priv, ENETDMA_BUFALLOC_FORCE_MASK | 0,
+ ENETDMA_BUFALLOC_REG(priv->rx_chan));
+
+ if (bcm_enet_refill_rx(dev)) {
+ dev_err(kdev, "cannot allocate rx skb queue\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* write rx & tx ring addresses */
+ enet_dmas_writel(priv, priv->rx_desc_dma,
+ ENETDMAS_RSTART_REG, priv->rx_chan);
+ enet_dmas_writel(priv, priv->tx_desc_dma,
+ ENETDMAS_RSTART_REG, priv->tx_chan);
+
+ /* clear remaining state ram for rx & tx channel */
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG, priv->rx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM2_REG, priv->tx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG, priv->rx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM3_REG, priv->tx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG, priv->rx_chan);
+ enet_dmas_writel(priv, 0, ENETDMAS_SRAM4_REG, priv->tx_chan);
+
+ /* set dma maximum burst len */
+ enet_dmac_writel(priv, priv->dma_maxburst,
+ ENETDMAC_MAXBURST, priv->rx_chan);
+ enet_dmac_writel(priv, priv->dma_maxburst,
+ ENETDMAC_MAXBURST, priv->tx_chan);
+
+ /* set flow control low/high threshold to 1/3 / 2/3 */
+ val = priv->rx_ring_size / 3;
+ enet_dma_writel(priv, val, ENETDMA_FLOWCL_REG(priv->rx_chan));
+ val = (priv->rx_ring_size * 2) / 3;
+ enet_dma_writel(priv, val, ENETDMA_FLOWCH_REG(priv->rx_chan));
+
+ /* all set, enable mac and interrupts, start dma engine and
+ * kick rx dma channel
+ */
+ wmb();
+ enet_dma_writel(priv, ENETDMA_CFG_EN_MASK, ENETDMA_CFG_REG);
+ enet_dmac_writel(priv, ENETDMAC_CHANCFG_EN_MASK,
+ ENETDMAC_CHANCFG, priv->rx_chan);
+
+ /* watch "packet transferred" interrupt in rx and tx */
+ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK,
+ ENETDMAC_IR, priv->rx_chan);
+ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK,
+ ENETDMAC_IR, priv->tx_chan);
+
+ /* make sure we enable napi before rx interrupt */
+ napi_enable(&priv->napi);
+
+ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK,
+ ENETDMAC_IRMASK, priv->rx_chan);
+ enet_dmac_writel(priv, ENETDMAC_IR_PKTDONE_MASK,
+ ENETDMAC_IRMASK, priv->tx_chan);
+
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+
+ /* apply override config for bypass_link ports here. */
+ for (i = 0; i < priv->num_ports; i++) {
+ struct bcm63xx_enetsw_port *port;
+ u8 override;
+ port = &priv->used_ports[i];
+ if (!port->used)
+ continue;
+
+ if (!port->bypass_link)
+ continue;
+
+ override = ENETSW_PORTOV_ENABLE_MASK |
+ ENETSW_PORTOV_LINKUP_MASK;
+
+ switch (port->force_speed) {
+ case 1000:
+ override |= ENETSW_IMPOV_1000_MASK;
+ break;
+ case 100:
+ override |= ENETSW_IMPOV_100_MASK;
+ break;
+ case 10:
+ break;
+ default:
+ pr_warn("invalid forced speed on port %s: assume 10\n",
+ port->name);
+ break;
+ }
+
+ if (port->force_duplex_full)
+ override |= ENETSW_IMPOV_FDX_MASK;
+
+
+ enetsw_writeb(priv, override, ENETSW_PORTOV_REG(i));
+ enetsw_writeb(priv, 0, ENETSW_PTCTRL_REG(i));
+ }
+
+ /* start phy polling timer */
+ init_timer(&priv->swphy_poll);
+ priv->swphy_poll.function = swphy_poll_timer;
+ priv->swphy_poll.data = (unsigned long)priv;
+ priv->swphy_poll.expires = jiffies;
+ add_timer(&priv->swphy_poll);
+ return 0;
+
+out:
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ struct bcm_enet_desc *desc;
+
+ if (!priv->rx_skb[i])
+ continue;
+
+ desc = &priv->rx_desc_cpu[i];
+ dma_unmap_single(kdev, desc->address, priv->rx_skb_size,
+ DMA_FROM_DEVICE);
+ kfree_skb(priv->rx_skb[i]);
+ }
+ kfree(priv->rx_skb);
+
+out_free_tx_skb:
+ kfree(priv->tx_skb);
+
+out_free_tx_ring:
+ dma_free_coherent(kdev, priv->tx_desc_alloc_size,
+ priv->tx_desc_cpu, priv->tx_desc_dma);
+
+out_free_rx_ring:
+ dma_free_coherent(kdev, priv->rx_desc_alloc_size,
+ priv->rx_desc_cpu, priv->rx_desc_dma);
+
+out_freeirq_tx:
+ if (priv->irq_tx != -1)
+ free_irq(priv->irq_tx, dev);
+
+out_freeirq_rx:
+ free_irq(priv->irq_rx, dev);
+
+out_freeirq:
+ return ret;
+}
+
+/* stop callback */
+static int bcm_enetsw_stop(struct net_device *dev)
+{
+ struct bcm_enet_priv *priv;
+ struct device *kdev;
+ int i;
+
+ priv = netdev_priv(dev);
+ kdev = &priv->pdev->dev;
+
+ del_timer_sync(&priv->swphy_poll);
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+ del_timer_sync(&priv->rx_timeout);
+
+ /* mask all interrupts */
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->rx_chan);
+ enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan);
+
+ /* disable dma & mac */
+ bcm_enet_disable_dma(priv, priv->tx_chan);
+ bcm_enet_disable_dma(priv, priv->rx_chan);
+
+ /* force reclaim of all tx buffers */
+ bcm_enet_tx_reclaim(dev, 1);
+
+ /* free the rx skb ring */
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ struct bcm_enet_desc *desc;
+
+ if (!priv->rx_skb[i])
+ continue;
+
+ desc = &priv->rx_desc_cpu[i];
+ dma_unmap_single(kdev, desc->address, priv->rx_skb_size,
+ DMA_FROM_DEVICE);
+ kfree_skb(priv->rx_skb[i]);
+ }
+
+ /* free remaining allocated memory */
+ kfree(priv->rx_skb);
+ kfree(priv->tx_skb);
+ dma_free_coherent(kdev, priv->rx_desc_alloc_size,
+ priv->rx_desc_cpu, priv->rx_desc_dma);
+ dma_free_coherent(kdev, priv->tx_desc_alloc_size,
+ priv->tx_desc_cpu, priv->tx_desc_dma);
+ if (priv->irq_tx != -1)
+ free_irq(priv->irq_tx, dev);
+ free_irq(priv->irq_rx, dev);
+
+ return 0;
+}
+
+/* try to sort out phy external status by walking the used_port field
+ * in the bcm_enet_priv structure. in case the phy address is not
+ * assigned to any physical port on the switch, assume it is external
+ * (and yell at the user).
+ */
+static int bcm_enetsw_phy_is_external(struct bcm_enet_priv *priv, int phy_id)
+{
+ int i;
+
+ for (i = 0; i < priv->num_ports; ++i) {
+ if (!priv->used_ports[i].used)
+ continue;
+ if (priv->used_ports[i].phy_id == phy_id)
+ return bcm_enet_port_is_rgmii(i);
+ }
+
+ printk_once(KERN_WARNING "bcm63xx_enet: could not find a used port with phy_id %i, assuming phy is external\n",
+ phy_id);
+ return 1;
+}
+
+/* can't use bcmenet_sw_mdio_read directly as we need to sort out
+ * external/internal status of the given phy_id first.
+ */
+static int bcm_enetsw_mii_mdio_read(struct net_device *dev, int phy_id,
+ int location)
+{
+ struct bcm_enet_priv *priv;
+
+ priv = netdev_priv(dev);
+ return bcmenet_sw_mdio_read(priv,
+ bcm_enetsw_phy_is_external(priv, phy_id),
+ phy_id, location);
+}
+
+/* can't use bcmenet_sw_mdio_write directly as we need to sort out
+ * external/internal status of the given phy_id first.
+ */
+static void bcm_enetsw_mii_mdio_write(struct net_device *dev, int phy_id,
+ int location,
+ int val)
+{
+ struct bcm_enet_priv *priv;
+
+ priv = netdev_priv(dev);
+ bcmenet_sw_mdio_write(priv, bcm_enetsw_phy_is_external(priv, phy_id),
+ phy_id, location, val);
+}
+
+static int bcm_enetsw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct mii_if_info mii;
+
+ mii.dev = dev;
+ mii.mdio_read = bcm_enetsw_mii_mdio_read;
+ mii.mdio_write = bcm_enetsw_mii_mdio_write;
+ mii.phy_id = 0;
+ mii.phy_id_mask = 0x3f;
+ mii.reg_num_mask = 0x1f;
+ return generic_mii_ioctl(&mii, if_mii(rq), cmd, NULL);
+
+}
+
+static const struct net_device_ops bcm_enetsw_ops = {
+ .ndo_open = bcm_enetsw_open,
+ .ndo_stop = bcm_enetsw_stop,
+ .ndo_start_xmit = bcm_enet_start_xmit,
+ .ndo_change_mtu = bcm_enet_change_mtu,
+ .ndo_do_ioctl = bcm_enetsw_ioctl,
+};
+
+
+static const struct bcm_enet_stats bcm_enetsw_gstrings_stats[] = {
+ { "rx_packets", DEV_STAT(rx_packets), -1 },
+ { "tx_packets", DEV_STAT(tx_packets), -1 },
+ { "rx_bytes", DEV_STAT(rx_bytes), -1 },
+ { "tx_bytes", DEV_STAT(tx_bytes), -1 },
+ { "rx_errors", DEV_STAT(rx_errors), -1 },
+ { "tx_errors", DEV_STAT(tx_errors), -1 },
+ { "rx_dropped", DEV_STAT(rx_dropped), -1 },
+ { "tx_dropped", DEV_STAT(tx_dropped), -1 },
+
+ { "tx_good_octets", GEN_STAT(mib.tx_gd_octets), ETHSW_MIB_RX_GD_OCT },
+ { "tx_unicast", GEN_STAT(mib.tx_unicast), ETHSW_MIB_RX_BRDCAST },
+ { "tx_broadcast", GEN_STAT(mib.tx_brdcast), ETHSW_MIB_RX_BRDCAST },
+ { "tx_multicast", GEN_STAT(mib.tx_mult), ETHSW_MIB_RX_MULT },
+ { "tx_64_octets", GEN_STAT(mib.tx_64), ETHSW_MIB_RX_64 },
+ { "tx_65_127_oct", GEN_STAT(mib.tx_65_127), ETHSW_MIB_RX_65_127 },
+ { "tx_128_255_oct", GEN_STAT(mib.tx_128_255), ETHSW_MIB_RX_128_255 },
+ { "tx_256_511_oct", GEN_STAT(mib.tx_256_511), ETHSW_MIB_RX_256_511 },
+ { "tx_512_1023_oct", GEN_STAT(mib.tx_512_1023), ETHSW_MIB_RX_512_1023},
+ { "tx_1024_1522_oct", GEN_STAT(mib.tx_1024_max),
+ ETHSW_MIB_RX_1024_1522 },
+ { "tx_1523_2047_oct", GEN_STAT(mib.tx_1523_2047),
+ ETHSW_MIB_RX_1523_2047 },
+ { "tx_2048_4095_oct", GEN_STAT(mib.tx_2048_4095),
+ ETHSW_MIB_RX_2048_4095 },
+ { "tx_4096_8191_oct", GEN_STAT(mib.tx_4096_8191),
+ ETHSW_MIB_RX_4096_8191 },
+ { "tx_8192_9728_oct", GEN_STAT(mib.tx_8192_9728),
+ ETHSW_MIB_RX_8192_9728 },
+ { "tx_oversize", GEN_STAT(mib.tx_ovr), ETHSW_MIB_RX_OVR },
+ { "tx_oversize_drop", GEN_STAT(mib.tx_ovr), ETHSW_MIB_RX_OVR_DISC },
+ { "tx_dropped", GEN_STAT(mib.tx_drop), ETHSW_MIB_RX_DROP },
+ { "tx_undersize", GEN_STAT(mib.tx_underrun), ETHSW_MIB_RX_UND },
+ { "tx_pause", GEN_STAT(mib.tx_pause), ETHSW_MIB_RX_PAUSE },
+
+ { "rx_good_octets", GEN_STAT(mib.rx_gd_octets), ETHSW_MIB_TX_ALL_OCT },
+ { "rx_broadcast", GEN_STAT(mib.rx_brdcast), ETHSW_MIB_TX_BRDCAST },
+ { "rx_multicast", GEN_STAT(mib.rx_mult), ETHSW_MIB_TX_MULT },
+ { "rx_unicast", GEN_STAT(mib.rx_unicast), ETHSW_MIB_TX_MULT },
+ { "rx_pause", GEN_STAT(mib.rx_pause), ETHSW_MIB_TX_PAUSE },
+ { "rx_dropped", GEN_STAT(mib.rx_drop), ETHSW_MIB_TX_DROP_PKTS },
+
+};
+
+#define BCM_ENETSW_STATS_LEN \
+ (sizeof(bcm_enetsw_gstrings_stats) / sizeof(struct bcm_enet_stats))
+
+static void bcm_enetsw_get_strings(struct net_device *netdev,
+ u32 stringset, u8 *data)
+{
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) {
+ memcpy(data + i * ETH_GSTRING_LEN,
+ bcm_enetsw_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ }
+ break;
+ }
+}
+
+static int bcm_enetsw_get_sset_count(struct net_device *netdev,
+ int string_set)
+{
+ switch (string_set) {
+ case ETH_SS_STATS:
+ return BCM_ENETSW_STATS_LEN;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void bcm_enetsw_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ strncpy(drvinfo->driver, bcm_enet_driver_name, 32);
+ strncpy(drvinfo->version, bcm_enet_driver_version, 32);
+ strncpy(drvinfo->fw_version, "N/A", 32);
+ strncpy(drvinfo->bus_info, "bcm63xx", 32);
+ drvinfo->n_stats = BCM_ENETSW_STATS_LEN;
+}
+
+static void bcm_enetsw_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct bcm_enet_priv *priv;
+ int i;
+
+ priv = netdev_priv(netdev);
+
+ for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) {
+ const struct bcm_enet_stats *s;
+ u32 lo, hi;
+ char *p;
+ int reg;
+
+ s = &bcm_enetsw_gstrings_stats[i];
+
+ reg = s->mib_reg;
+ if (reg == -1)
+ continue;
+
+ lo = enetsw_readl(priv, ENETSW_MIB_REG(reg));
+ p = (char *)priv + s->stat_offset;
+
+ if (s->sizeof_stat == sizeof(u64)) {
+ hi = enetsw_readl(priv, ENETSW_MIB_REG(reg + 1));
+ *(u64 *)p = ((u64)hi << 32 | lo);
+ } else {
+ *(u32 *)p = lo;
+ }
+ }
+
+ for (i = 0; i < BCM_ENETSW_STATS_LEN; i++) {
+ const struct bcm_enet_stats *s;
+ char *p;
+
+ s = &bcm_enetsw_gstrings_stats[i];
+
+ if (s->mib_reg == -1)
+ p = (char *)&netdev->stats + s->stat_offset;
+ else
+ p = (char *)priv + s->stat_offset;
+
+ data[i] = (s->sizeof_stat == sizeof(u64)) ?
+ *(u64 *)p : *(u32 *)p;
+ }
+}
+
+static void bcm_enetsw_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ering)
+{
+ struct bcm_enet_priv *priv;
+
+ priv = netdev_priv(dev);
+
+ /* rx/tx ring is actually only limited by memory */
+ ering->rx_max_pending = 8192;
+ ering->tx_max_pending = 8192;
+ ering->rx_mini_max_pending = 0;
+ ering->rx_jumbo_max_pending = 0;
+ ering->rx_pending = priv->rx_ring_size;
+ ering->tx_pending = priv->tx_ring_size;
+}
+
+static int bcm_enetsw_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ering)
+{
+ struct bcm_enet_priv *priv;
+ int was_running;
+
+ priv = netdev_priv(dev);
+
+ was_running = 0;
+ if (netif_running(dev)) {
+ bcm_enetsw_stop(dev);
+ was_running = 1;
+ }
+
+ priv->rx_ring_size = ering->rx_pending;
+ priv->tx_ring_size = ering->tx_pending;
+
+ if (was_running) {
+ int err;
+
+ err = bcm_enetsw_open(dev);
+ if (err)
+ dev_close(dev);
+ }
+ return 0;
+}
+
+static struct ethtool_ops bcm_enetsw_ethtool_ops = {
+ .get_strings = bcm_enetsw_get_strings,
+ .get_sset_count = bcm_enetsw_get_sset_count,
+ .get_ethtool_stats = bcm_enetsw_get_ethtool_stats,
+ .get_drvinfo = bcm_enetsw_get_drvinfo,
+ .get_ringparam = bcm_enetsw_get_ringparam,
+ .set_ringparam = bcm_enetsw_set_ringparam,
+};
+
+/* allocate netdevice, request register memory and register device. */
+static int bcm_enetsw_probe(struct platform_device *pdev)
+{
+ struct bcm_enet_priv *priv;
+ struct net_device *dev;
+ struct bcm63xx_enetsw_platform_data *pd;
+ struct resource *res_mem;
+ int ret, irq_rx, irq_tx;
+
+ /* stop if shared driver failed, assume driver->probe will be
+ * called in the same order we register devices (correct ?)
+ */
+ if (!bcm_enet_shared_base[0])
+ return -ENODEV;
+
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq_rx = platform_get_irq(pdev, 0);
+ irq_tx = platform_get_irq(pdev, 1);
+ if (!res_mem || irq_rx < 0)
return -ENODEV;
- bcm_enet_shared_base = devm_request_and_ioremap(&pdev->dev, res);
- if (!bcm_enet_shared_base)
+ ret = 0;
+ dev = alloc_etherdev(sizeof(*priv));
+ if (!dev)
return -ENOMEM;
+ priv = netdev_priv(dev);
+ memset(priv, 0, sizeof(*priv));
+
+ /* initialize default and fetch platform data */
+ priv->enet_is_sw = true;
+ priv->irq_rx = irq_rx;
+ priv->irq_tx = irq_tx;
+ priv->rx_ring_size = BCMENET_DEF_RX_DESC;
+ priv->tx_ring_size = BCMENET_DEF_TX_DESC;
+ priv->dma_maxburst = BCMENETSW_DMA_MAXBURST;
+
+ pd = pdev->dev.platform_data;
+ if (pd) {
+ memcpy(dev->dev_addr, pd->mac_addr, ETH_ALEN);
+ memcpy(priv->used_ports, pd->used_ports,
+ sizeof(pd->used_ports));
+ priv->num_ports = pd->num_ports;
+ priv->dma_has_sram = pd->dma_has_sram;
+ priv->dma_chan_en_mask = pd->dma_chan_en_mask;
+ priv->dma_chan_int_mask = pd->dma_chan_int_mask;
+ priv->dma_chan_width = pd->dma_chan_width;
+ }
+
+ ret = compute_hw_mtu(priv, dev->mtu);
+ if (ret)
+ goto out;
+
+ if (!request_mem_region(res_mem->start, resource_size(res_mem),
+ "bcm63xx_enetsw")) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ priv->base = ioremap(res_mem->start, resource_size(res_mem));
+ if (priv->base == NULL) {
+ ret = -ENOMEM;
+ goto out_release_mem;
+ }
+
+ priv->mac_clk = clk_get(&pdev->dev, "enetsw");
+ if (IS_ERR(priv->mac_clk)) {
+ ret = PTR_ERR(priv->mac_clk);
+ goto out_unmap;
+ }
+ clk_enable(priv->mac_clk);
+
+ priv->rx_chan = 0;
+ priv->tx_chan = 1;
+ spin_lock_init(&priv->rx_lock);
+
+ /* init rx timeout (used for oom) */
+ init_timer(&priv->rx_timeout);
+ priv->rx_timeout.function = bcm_enet_refill_rx_timer;
+ priv->rx_timeout.data = (unsigned long)dev;
+
+ /* register netdevice */
+ dev->netdev_ops = &bcm_enetsw_ops;
+ netif_napi_add(dev, &priv->napi, bcm_enet_poll, 16);
+ SET_ETHTOOL_OPS(dev, &bcm_enetsw_ethtool_ops);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ spin_lock_init(&priv->enetsw_mdio_lock);
+
+ ret = register_netdev(dev);
+ if (ret)
+ goto out_put_clk;
+
+ netif_carrier_off(dev);
+ platform_set_drvdata(pdev, dev);
+ priv->pdev = pdev;
+ priv->net_dev = dev;
+
+ return 0;
+
+out_put_clk:
+ clk_put(priv->mac_clk);
+
+out_unmap:
+ iounmap(priv->base);
+
+out_release_mem:
+ release_mem_region(res_mem->start, resource_size(res_mem));
+out:
+ free_netdev(dev);
+ return ret;
+}
+
+
+/* exit func, stops hardware and unregisters netdevice */
+static int bcm_enetsw_remove(struct platform_device *pdev)
+{
+ struct bcm_enet_priv *priv;
+ struct net_device *dev;
+ struct resource *res;
+
+ /* stop netdevice */
+ dev = platform_get_drvdata(pdev);
+ priv = netdev_priv(dev);
+ unregister_netdev(dev);
+
+ /* release device resources */
+ iounmap(priv->base);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, resource_size(res));
+
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(dev);
+ return 0;
+}
+
+struct platform_driver bcm63xx_enetsw_driver = {
+ .probe = bcm_enetsw_probe,
+ .remove = bcm_enetsw_remove,
+ .driver = {
+ .name = "bcm63xx_enetsw",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* reserve & remap memory space shared between all macs */
+static int bcm_enet_shared_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *p[3];
+ unsigned int i;
+
+ memset(bcm_enet_shared_base, 0, sizeof(bcm_enet_shared_base));
+
+ for (i = 0; i < 3; i++) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ p[i] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(p[i]))
+ return PTR_ERR(p[i]);
+ }
+
+ memcpy(bcm_enet_shared_base, p, sizeof(bcm_enet_shared_base));
return 0;
}
@@ -1884,8 +2876,7 @@ static int bcm_enet_shared_remove(struct platform_device *pdev)
return 0;
}
-/*
- * this "shared" driver is needed because both macs share a single
+/* this "shared" driver is needed because both macs share a single
* address space
*/
struct platform_driver bcm63xx_enet_shared_driver = {
@@ -1897,9 +2888,7 @@ struct platform_driver bcm63xx_enet_shared_driver = {
},
};
-/*
- * entry point
- */
+/* entry point */
static int __init bcm_enet_init(void)
{
int ret;
@@ -1912,12 +2901,19 @@ static int __init bcm_enet_init(void)
if (ret)
platform_driver_unregister(&bcm63xx_enet_shared_driver);
+ ret = platform_driver_register(&bcm63xx_enetsw_driver);
+ if (ret) {
+ platform_driver_unregister(&bcm63xx_enet_driver);
+ platform_driver_unregister(&bcm63xx_enet_shared_driver);
+ }
+
return ret;
}
static void __exit bcm_enet_exit(void)
{
platform_driver_unregister(&bcm63xx_enet_driver);
+ platform_driver_unregister(&bcm63xx_enetsw_driver);
platform_driver_unregister(&bcm63xx_enet_shared_driver);
}
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.h b/drivers/net/ethernet/broadcom/bcm63xx_enet.h
index 133d585..f55af43 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.h
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.h
@@ -18,6 +18,7 @@
/* maximum burst len for dma (4 bytes unit) */
#define BCMENET_DMA_MAXBURST 16
+#define BCMENETSW_DMA_MAXBURST 8
/* tx transmit threshold (4 bytes unit), fifo is 256 bytes, the value
* must be low enough so that a DMA transfer of above burst length can
@@ -84,11 +85,60 @@
#define ETH_MIB_RX_CNTRL 54
+/*
+ * SW MIB Counters register definitions
+*/
+#define ETHSW_MIB_TX_ALL_OCT 0
+#define ETHSW_MIB_TX_DROP_PKTS 2
+#define ETHSW_MIB_TX_QOS_PKTS 3
+#define ETHSW_MIB_TX_BRDCAST 4
+#define ETHSW_MIB_TX_MULT 5
+#define ETHSW_MIB_TX_UNI 6
+#define ETHSW_MIB_TX_COL 7
+#define ETHSW_MIB_TX_1_COL 8
+#define ETHSW_MIB_TX_M_COL 9
+#define ETHSW_MIB_TX_DEF 10
+#define ETHSW_MIB_TX_LATE 11
+#define ETHSW_MIB_TX_EX_COL 12
+#define ETHSW_MIB_TX_PAUSE 14
+#define ETHSW_MIB_TX_QOS_OCT 15
+
+#define ETHSW_MIB_RX_ALL_OCT 17
+#define ETHSW_MIB_RX_UND 19
+#define ETHSW_MIB_RX_PAUSE 20
+#define ETHSW_MIB_RX_64 21
+#define ETHSW_MIB_RX_65_127 22
+#define ETHSW_MIB_RX_128_255 23
+#define ETHSW_MIB_RX_256_511 24
+#define ETHSW_MIB_RX_512_1023 25
+#define ETHSW_MIB_RX_1024_1522 26
+#define ETHSW_MIB_RX_OVR 27
+#define ETHSW_MIB_RX_JAB 28
+#define ETHSW_MIB_RX_ALIGN 29
+#define ETHSW_MIB_RX_CRC 30
+#define ETHSW_MIB_RX_GD_OCT 31
+#define ETHSW_MIB_RX_DROP 33
+#define ETHSW_MIB_RX_UNI 34
+#define ETHSW_MIB_RX_MULT 35
+#define ETHSW_MIB_RX_BRDCAST 36
+#define ETHSW_MIB_RX_SA_CHANGE 37
+#define ETHSW_MIB_RX_FRAG 38
+#define ETHSW_MIB_RX_OVR_DISC 39
+#define ETHSW_MIB_RX_SYM 40
+#define ETHSW_MIB_RX_QOS_PKTS 41
+#define ETHSW_MIB_RX_QOS_OCT 42
+#define ETHSW_MIB_RX_1523_2047 44
+#define ETHSW_MIB_RX_2048_4095 45
+#define ETHSW_MIB_RX_4096_8191 46
+#define ETHSW_MIB_RX_8192_9728 47
+
+
struct bcm_enet_mib_counters {
u64 tx_gd_octets;
u32 tx_gd_pkts;
u32 tx_all_octets;
u32 tx_all_pkts;
+ u32 tx_unicast;
u32 tx_brdcast;
u32 tx_mult;
u32 tx_64;
@@ -97,7 +147,12 @@ struct bcm_enet_mib_counters {
u32 tx_256_511;
u32 tx_512_1023;
u32 tx_1024_max;
+ u32 tx_1523_2047;
+ u32 tx_2048_4095;
+ u32 tx_4096_8191;
+ u32 tx_8192_9728;
u32 tx_jab;
+ u32 tx_drop;
u32 tx_ovr;
u32 tx_frag;
u32 tx_underrun;
@@ -114,6 +169,7 @@ struct bcm_enet_mib_counters {
u32 rx_all_octets;
u32 rx_all_pkts;
u32 rx_brdcast;
+ u32 rx_unicast;
u32 rx_mult;
u32 rx_64;
u32 rx_65_127;
@@ -197,6 +253,9 @@ struct bcm_enet_priv {
/* number of dma desc in tx ring */
int tx_ring_size;
+ /* maximum dma burst size */
+ int dma_maxburst;
+
/* cpu view of rx dma ring */
struct bcm_enet_desc *tx_desc_cpu;
@@ -269,6 +328,33 @@ struct bcm_enet_priv {
/* maximum hardware transmit/receive size */
unsigned int hw_mtu;
+
+ bool enet_is_sw;
+
+ /* port mapping for switch devices */
+ int num_ports;
+ struct bcm63xx_enetsw_port used_ports[ENETSW_MAX_PORT];
+ int sw_port_link[ENETSW_MAX_PORT];
+
+ /* used to poll switch port state */
+ struct timer_list swphy_poll;
+ spinlock_t enetsw_mdio_lock;
+
+ /* dma channel enable mask */
+ u32 dma_chan_en_mask;
+
+ /* dma channel interrupt mask */
+ u32 dma_chan_int_mask;
+
+ /* DMA engine has internal SRAM */
+ bool dma_has_sram;
+
+ /* dma channel width */
+ unsigned int dma_chan_width;
+
+ /* dma descriptor shift value */
+ unsigned int dma_desc_shift;
};
+
#endif /* ! BCM63XX_ENET_H_ */
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 5d20449..6a2de1d 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -8104,7 +8104,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
pci_set_master(pdev);
- bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ bp->pm_cap = pdev->pm_cap;
if (bp->pm_cap == 0) {
dev_err(&pdev->dev,
"Cannot find power management capability, aborting\n");
@@ -8764,18 +8764,4 @@ static struct pci_driver bnx2_pci_driver = {
.err_handler = &bnx2_err_handler,
};
-static int __init bnx2_init(void)
-{
- return pci_register_driver(&bnx2_pci_driver);
-}
-
-static void __exit bnx2_cleanup(void)
-{
- pci_unregister_driver(&bnx2_pci_driver);
-}
-
-module_init(bnx2_init);
-module_exit(bnx2_cleanup);
-
-
-
+module_pci_driver(bnx2_pci_driver);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 3dba2a7..edda716 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -34,12 +34,10 @@
#define BCM_DCBNL
#endif
-
#include "bnx2x_hsi.h"
#include "../cnic_if.h"
-
#define BNX2X_MIN_MSIX_VEC_CNT(bp) ((bp)->min_msix_vec_cnt)
#include <linux/mdio.h>
@@ -114,7 +112,6 @@ do { \
#define BNX2X_ERROR(fmt, ...) \
pr_err("[%s:%d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
-
/* before we have a dev->name use dev_info() */
#define BNX2X_DEV_INFO(fmt, ...) \
do { \
@@ -147,7 +144,6 @@ do { \
#define U64_HI(x) ((u32)(((u64)(x)) >> 32))
#define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo))
-
#define REG_ADDR(bp, offset) ((bp->regview) + (offset))
#define REG_RD(bp, offset) readl(REG_ADDR(bp, offset))
@@ -366,7 +362,7 @@ union db_prod {
/*
* Number of required SGEs is the sum of two:
* 1. Number of possible opened aggregations (next packet for
- * these aggregations will probably consume SGE immidiatelly)
+ * these aggregations will probably consume SGE immediately)
* 2. Rest of BRB blocks divided by 2 (block will consume new SGE only
* after placement on BD for new TPA aggregation)
*
@@ -387,7 +383,6 @@ union db_prod {
#define BIT_VEC64_ELEM_SHIFT 6
#define BIT_VEC64_ELEM_MASK ((u64)BIT_VEC64_ELEM_SZ - 1)
-
#define __BIT_VEC64_SET_BIT(el, bit) \
do { \
el = ((el) | ((u64)0x1 << (bit))); \
@@ -398,7 +393,6 @@ union db_prod {
el = ((el) & (~((u64)0x1 << (bit)))); \
} while (0)
-
#define BIT_VEC64_SET_BIT(vec64, idx) \
__BIT_VEC64_SET_BIT((vec64)[(idx) >> BIT_VEC64_ELEM_SHIFT], \
(idx) & BIT_VEC64_ELEM_MASK)
@@ -419,8 +413,6 @@ union db_prod {
/*******************************************************/
-
-
/* Number of u64 elements in SGE mask array */
#define RX_SGE_MASK_LEN (NUM_RX_SGE / BIT_VEC64_ELEM_SZ)
#define RX_SGE_MASK_LEN_MASK (RX_SGE_MASK_LEN - 1)
@@ -493,11 +485,26 @@ struct bnx2x_fastpath {
struct bnx2x *bp; /* parent */
struct napi_struct napi;
+
+#ifdef CONFIG_NET_LL_RX_POLL
+ unsigned int state;
+#define BNX2X_FP_STATE_IDLE 0
+#define BNX2X_FP_STATE_NAPI (1 << 0) /* NAPI owns this FP */
+#define BNX2X_FP_STATE_POLL (1 << 1) /* poll owns this FP */
+#define BNX2X_FP_STATE_NAPI_YIELD (1 << 2) /* NAPI yielded this FP */
+#define BNX2X_FP_STATE_POLL_YIELD (1 << 3) /* poll yielded this FP */
+#define BNX2X_FP_YIELD (BNX2X_FP_STATE_NAPI_YIELD | BNX2X_FP_STATE_POLL_YIELD)
+#define BNX2X_FP_LOCKED (BNX2X_FP_STATE_NAPI | BNX2X_FP_STATE_POLL)
+#define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD)
+ /* protect state */
+ spinlock_t lock;
+#endif /* CONFIG_NET_LL_RX_POLL */
+
union host_hc_status_block status_blk;
- /* chip independed shortcuts into sb structure */
+ /* chip independent shortcuts into sb structure */
__le16 *sb_index_values;
__le16 *sb_running_index;
- /* chip independed shortcut into rx_prods_offset memory */
+ /* chip independent shortcut into rx_prods_offset memory */
u32 ustorm_rx_prods_offset;
u32 rx_buf_size;
@@ -565,6 +572,116 @@ struct bnx2x_fastpath {
#define bnx2x_fp_stats(bp, fp) (&((bp)->fp_stats[(fp)->index]))
#define bnx2x_fp_qstats(bp, fp) (&((bp)->fp_stats[(fp)->index].eth_q_stats))
+#ifdef CONFIG_NET_LL_RX_POLL
+static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp)
+{
+ spin_lock_init(&fp->lock);
+ fp->state = BNX2X_FP_STATE_IDLE;
+}
+
+/* called from the device poll routine to get ownership of a FP */
+static inline bool bnx2x_fp_lock_napi(struct bnx2x_fastpath *fp)
+{
+ bool rc = true;
+
+ spin_lock(&fp->lock);
+ if (fp->state & BNX2X_FP_LOCKED) {
+ WARN_ON(fp->state & BNX2X_FP_STATE_NAPI);
+ fp->state |= BNX2X_FP_STATE_NAPI_YIELD;
+ rc = false;
+ } else {
+ /* we don't care if someone yielded */
+ fp->state = BNX2X_FP_STATE_NAPI;
+ }
+ spin_unlock(&fp->lock);
+ return rc;
+}
+
+/* returns true is someone tried to get the FP while napi had it */
+static inline bool bnx2x_fp_unlock_napi(struct bnx2x_fastpath *fp)
+{
+ bool rc = false;
+
+ spin_lock(&fp->lock);
+ WARN_ON(fp->state &
+ (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_NAPI_YIELD));
+
+ if (fp->state & BNX2X_FP_STATE_POLL_YIELD)
+ rc = true;
+ fp->state = BNX2X_FP_STATE_IDLE;
+ spin_unlock(&fp->lock);
+ return rc;
+}
+
+/* called from bnx2x_low_latency_poll() */
+static inline bool bnx2x_fp_lock_poll(struct bnx2x_fastpath *fp)
+{
+ bool rc = true;
+
+ spin_lock_bh(&fp->lock);
+ if ((fp->state & BNX2X_FP_LOCKED)) {
+ fp->state |= BNX2X_FP_STATE_POLL_YIELD;
+ rc = false;
+ } else {
+ /* preserve yield marks */
+ fp->state |= BNX2X_FP_STATE_POLL;
+ }
+ spin_unlock_bh(&fp->lock);
+ return rc;
+}
+
+/* returns true if someone tried to get the FP while it was locked */
+static inline bool bnx2x_fp_unlock_poll(struct bnx2x_fastpath *fp)
+{
+ bool rc = false;
+
+ spin_lock_bh(&fp->lock);
+ WARN_ON(fp->state & BNX2X_FP_STATE_NAPI);
+
+ if (fp->state & BNX2X_FP_STATE_POLL_YIELD)
+ rc = true;
+ fp->state = BNX2X_FP_STATE_IDLE;
+ spin_unlock_bh(&fp->lock);
+ return rc;
+}
+
+/* true if a socket is polling, even if it did not get the lock */
+static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp)
+{
+ WARN_ON(!(fp->state & BNX2X_FP_LOCKED));
+ return fp->state & BNX2X_FP_USER_PEND;
+}
+#else
+static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp)
+{
+}
+
+static inline bool bnx2x_fp_lock_napi(struct bnx2x_fastpath *fp)
+{
+ return true;
+}
+
+static inline bool bnx2x_fp_unlock_napi(struct bnx2x_fastpath *fp)
+{
+ return false;
+}
+
+static inline bool bnx2x_fp_lock_poll(struct bnx2x_fastpath *fp)
+{
+ return false;
+}
+
+static inline bool bnx2x_fp_unlock_poll(struct bnx2x_fastpath *fp)
+{
+ return false;
+}
+
+static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp)
+{
+ return false;
+}
+#endif /* CONFIG_NET_LL_RX_POLL */
+
/* Use 2500 as a mini-jumbo MTU for FCoE */
#define BNX2X_FCOE_MINI_JUMBO_MTU 2500
@@ -580,12 +697,10 @@ struct bnx2x_fastpath {
txdata_ptr[FIRST_TX_COS_INDEX] \
->var)
-
#define IS_ETH_FP(fp) ((fp)->index < BNX2X_NUM_ETH_QUEUES((fp)->bp))
#define IS_FCOE_FP(fp) ((fp)->index == FCOE_IDX((fp)->bp))
#define IS_FCOE_IDX(idx) ((idx) == FCOE_IDX(bp))
-
/* MC hsi */
#define MAX_FETCH_BD 13 /* HW max BDs per packet */
#define RX_COPY_THRESH 92
@@ -613,7 +728,7 @@ struct bnx2x_fastpath {
* START_BD(splitted) - includes unpaged data segment for GSO
* PARSING_BD - for TSO and CSUM data
* PARSING_BD2 - for encapsulation data
- * Frag BDs - decribes pages for frags
+ * Frag BDs - describes pages for frags
*/
#define BDS_PER_TX_PKT 4
#define MAX_BDS_PER_TX_PKT (MAX_SKB_FRAGS + BDS_PER_TX_PKT)
@@ -693,12 +808,10 @@ struct bnx2x_fastpath {
FW_DROP_LEVEL(bp))
#define RCQ_TH_HI(bp) (RCQ_TH_LO(bp) + DROPLESS_FC_HEADROOM)
-
/* This is needed for determining of last_max */
#define SUB_S16(a, b) (s16)((s16)(a) - (s16)(b))
#define SUB_S32(a, b) (s32)((s32)(a) - (s32)(b))
-
#define BNX2X_SWCID_SHIFT 17
#define BNX2X_SWCID_MASK ((0x1 << BNX2X_SWCID_SHIFT) - 1)
@@ -723,7 +836,6 @@ struct bnx2x_fastpath {
DPM_TRIGER_TYPE); \
} while (0)
-
/* TX CSUM helpers */
#define SKB_CS_OFF(skb) (offsetof(struct tcphdr, check) - \
skb->csum_offset)
@@ -766,7 +878,6 @@ struct bnx2x_fastpath {
#define BNX2X_RX_SUM_FIX(cqe) \
BNX2X_PRS_FLAG_OVERETH_IPV4(cqe->fast_path_cqe.pars_flags.flags)
-
#define FP_USB_FUNC_OFF \
offsetof(struct cstorm_status_block_u, func)
#define FP_CSB_FUNC_OFF \
@@ -900,14 +1011,14 @@ struct bnx2x_common {
#define CHIP_IS_E3A0(bp) (CHIP_IS_E3(bp) && \
(CHIP_REV(bp) == CHIP_REV_Ax))
/* This define is used in two main places:
- * 1. In the early stages of nic_load, to know if to configrue Parser / Searcher
+ * 1. In the early stages of nic_load, to know if to configure Parser / Searcher
* to nic-only mode or to offload mode. Offload mode is configured if either the
* chip is E1x (where MIC_MODE register is not applicable), or if cnic already
* registered for this port (which means that the user wants storage services).
* 2. During cnic-related load, to know if offload mode is already configured in
- * the HW or needs to be configrued.
+ * the HW or needs to be configured.
* Since the transition from nic-mode to offload-mode in HW causes traffic
- * coruption, nic-mode is configured only in ports on which storage services
+ * corruption, nic-mode is configured only in ports on which storage services
* where never requested.
*/
#define CONFIGURE_NIC_MODE(bp) (!CHIP_IS_E1x(bp) && !CNIC_ENABLED(bp))
@@ -1008,14 +1119,14 @@ extern struct workqueue_struct *bnx2x_wq;
* If the maximum number of FP-SB available is X then:
* a. If CNIC is supported it consumes 1 FP-SB thus the max number of
* regular L2 queues is Y=X-1
- * b. in MF mode the actual number of L2 queues is Y= (X-1/MF_factor)
+ * b. In MF mode the actual number of L2 queues is Y= (X-1/MF_factor)
* c. If the FCoE L2 queue is supported the actual number of L2 queues
* is Y+1
* d. The number of irqs (MSIX vectors) is either Y+1 (one extra for
* slow-path interrupts) or Y+2 if CNIC is supported (one additional
* FP interrupt context for the CNIC).
* e. The number of HW context (CID count) is always X or X+1 if FCoE
- * L2 queue is supported. the cid for the FCoE L2 queue is always X.
+ * L2 queue is supported. The cid for the FCoE L2 queue is always X.
*/
/* fast-path interrupt contexts E1x */
@@ -1068,7 +1179,6 @@ struct bnx2x_slowpath {
struct eth_classify_rules_ramrod_data e2;
} mac_rdata;
-
union {
struct tstorm_eth_mac_filter_config e1x;
struct eth_filter_rules_ramrod_data e2;
@@ -1119,7 +1229,6 @@ struct bnx2x_slowpath {
#define bnx2x_sp_mapping(bp, var) \
(bp->slowpath_mapping + offsetof(struct bnx2x_slowpath, var))
-
/* attn group wiring */
#define MAX_DYNAMIC_ATTN_GRPS 8
@@ -1225,7 +1334,6 @@ enum {
BNX2X_SP_RTNL_HYPERVISOR_VLAN,
};
-
struct bnx2x_prev_path_list {
struct list_head list;
u8 bus;
@@ -1585,7 +1693,7 @@ struct bnx2x {
struct mutex cnic_mutex;
struct bnx2x_vlan_mac_obj iscsi_l2_mac_obj;
- /* Start index of the "special" (CNIC related) L2 cleints */
+ /* Start index of the "special" (CNIC related) L2 clients */
u8 cnic_base_cl_id;
int dmae_ready;
@@ -1699,7 +1807,7 @@ struct bnx2x {
/* operation indication for the sp_rtnl task */
unsigned long sp_rtnl_state;
- /* DCBX Negotation results */
+ /* DCBX Negotiation results */
struct dcbx_features dcbx_local_feat;
u32 dcbx_error;
@@ -1755,7 +1863,6 @@ extern int num_queues;
#define FUNC_FLG_SPQ 0x0010
#define FUNC_FLG_LEADING 0x0020 /* PF only */
-
struct bnx2x_func_init_params {
/* dma */
dma_addr_t fw_stat_map; /* valid iff FUNC_FLG_STATS */
@@ -1853,9 +1960,6 @@ struct bnx2x_func_init_params {
#define skip_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx))
-
-
-
/**
* bnx2x_set_mac_one - configure a single MAC address
*
@@ -1921,7 +2025,6 @@ u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
void bnx2x_prep_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
u8 src_type, u8 dst_type);
int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae);
-void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl);
/* FLR related routines */
u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp);
@@ -1937,6 +2040,8 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
void bnx2x_update_coalesce(struct bnx2x *bp);
int bnx2x_get_cur_phy_idx(struct bnx2x *bp);
+bool bnx2x_port_after_undi(struct bnx2x *bp);
+
static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
int wait)
{
@@ -1998,7 +2103,6 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
#define UNLOAD_CLOSE 1
#define UNLOAD_RECOVERY 2
-
/* DMAE command defines */
#define DMAE_TIMEOUT -1
#define DMAE_PCI_ERROR -2 /* E2 and onward */
@@ -2062,7 +2166,8 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
#define DMAE_LEN32_WR_MAX(bp) (CHIP_IS_E1(bp) ? 0x400 : 0x2000)
#define DMAE_COMP_VAL 0x60d0d0ae /* E2 and on - upper bit
- indicates eror */
+ * indicates error
+ */
#define MAX_DMAE_C_PER_PORT 8
#define INIT_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \
@@ -2100,7 +2205,6 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
#define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe))
#define MAX_SP_DESC_CNT (SP_DESC_CNT - 1)
-
#define BNX2X_BTR 4
#define MAX_SPQ_PENDING 8
@@ -2137,6 +2241,8 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
#define ATTN_HARD_WIRED_MASK 0xff00
#define ATTENTION_ID 4
+#define IS_MF_STORAGE_ONLY(bp) (IS_MF_STORAGE_SD(bp) || \
+ IS_MF_FCOE_AFEX(bp))
/* stuff added to make the code fit 80Col */
@@ -2338,4 +2444,9 @@ enum {
#define NUM_MACS 8
+enum bnx2x_pci_bus_speed {
+ BNX2X_PCI_LINK_SPEED_2500 = 2500,
+ BNX2X_PCI_LINK_SPEED_5000 = 5000,
+ BNX2X_PCI_LINK_SPEED_8000 = 8000
+};
#endif /* bnx2x.h */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index b8fbe26..ca7f2bb 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -24,6 +24,7 @@
#include <net/tcp.h>
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
+#include <net/ll_poll.h>
#include <linux/prefetch.h>
#include "bnx2x_cmn.h"
#include "bnx2x_init.h"
@@ -124,7 +125,7 @@ static void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta)
int i, cos, old_eth_num = BNX2X_NUM_ETH_QUEUES(bp);
/* Queue pointer cannot be re-set on an fp-basis, as moving pointer
- * backward along the array could cause memory to be overriden
+ * backward along the array could cause memory to be overridden
*/
for (cos = 1; cos < bp->max_cos; cos++) {
for (i = 0; i < old_eth_num - delta; i++) {
@@ -165,7 +166,6 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata,
dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd),
BD_UNMAP_LEN(tx_start_bd), DMA_TO_DEVICE);
-
nbd = le16_to_cpu(tx_start_bd->nbd) - 1;
#ifdef BNX2X_STOP_ON_ERROR
if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) {
@@ -259,7 +259,7 @@ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata)
smp_mb();
if (unlikely(netif_tx_queue_stopped(txq))) {
- /* Taking tx_lock() is needed to prevent reenabling the queue
+ /* Taking tx_lock() is needed to prevent re-enabling the queue
* while it's empty. This could have happen if rx_action() gets
* suspended in bnx2x_tx_int() after the condition before
* netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()):
@@ -572,7 +572,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
return err;
}
- /* Unmap the page as we r going to pass it to the stack */
+ /* Unmap the page as we're going to pass it to the stack */
dma_unmap_page(&bp->pdev->dev,
dma_unmap_addr(&old_rx_pg, mapping),
SGE_PAGES, DMA_FROM_DEVICE);
@@ -733,7 +733,6 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
dev_kfree_skb_any(skb);
}
-
/* put new data in bin */
rx_buf->data = new_data;
@@ -805,40 +804,32 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
{
struct bnx2x *bp = fp->bp;
u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons;
- u16 hw_comp_cons, sw_comp_cons, sw_comp_prod;
+ u16 sw_comp_cons, sw_comp_prod;
int rx_pkt = 0;
+ union eth_rx_cqe *cqe;
+ struct eth_fast_path_rx_cqe *cqe_fp;
#ifdef BNX2X_STOP_ON_ERROR
if (unlikely(bp->panic))
return 0;
#endif
- /* CQ "next element" is of the size of the regular element,
- that's why it's ok here */
- hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb);
- if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
- hw_comp_cons++;
-
bd_cons = fp->rx_bd_cons;
bd_prod = fp->rx_bd_prod;
bd_prod_fw = bd_prod;
sw_comp_cons = fp->rx_comp_cons;
sw_comp_prod = fp->rx_comp_prod;
- /* Memory barrier necessary as speculative reads of the rx
- * buffer can be ahead of the index in the status block
- */
- rmb();
+ comp_ring_cons = RCQ_BD(sw_comp_cons);
+ cqe = &fp->rx_comp_ring[comp_ring_cons];
+ cqe_fp = &cqe->fast_path_cqe;
DP(NETIF_MSG_RX_STATUS,
- "queue[%d]: hw_comp_cons %u sw_comp_cons %u\n",
- fp->index, hw_comp_cons, sw_comp_cons);
+ "queue[%d]: sw_comp_cons %u\n", fp->index, sw_comp_cons);
- while (sw_comp_cons != hw_comp_cons) {
+ while (BNX2X_IS_CQE_COMPLETED(cqe_fp)) {
struct sw_rx_bd *rx_buf = NULL;
struct sk_buff *skb;
- union eth_rx_cqe *cqe;
- struct eth_fast_path_rx_cqe *cqe_fp;
u8 cqe_fp_flags;
enum eth_rx_cqe_type cqe_fp_type;
u16 len, pad, queue;
@@ -850,12 +841,9 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
return 0;
#endif
- comp_ring_cons = RCQ_BD(sw_comp_cons);
bd_prod = RX_BD(bd_prod);
bd_cons = RX_BD(bd_cons);
- cqe = &fp->rx_comp_ring[comp_ring_cons];
- cqe_fp = &cqe->fast_path_cqe;
cqe_fp_flags = cqe_fp->type_error_flags;
cqe_fp_type = cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE;
@@ -899,7 +887,6 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
cqe_fp);
goto next_rx;
-
}
queue = cqe->end_agg_cqe.queue_index;
tpa_info = &fp->tpa_info[queue];
@@ -1002,9 +989,13 @@ reuse_rx:
PARSING_FLAGS_VLAN)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
le16_to_cpu(cqe_fp->vlan_tag));
- napi_gro_receive(&fp->napi, skb);
+ skb_mark_ll(skb, &fp->napi);
+ if (bnx2x_fp_ll_polling(fp))
+ netif_receive_skb(skb);
+ else
+ napi_gro_receive(&fp->napi, skb);
next_rx:
rx_buf->data = NULL;
@@ -1016,8 +1007,15 @@ next_cqe:
sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod);
sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons);
+ /* mark CQE as free */
+ BNX2X_SEED_CQE(cqe_fp);
+
if (rx_pkt == budget)
break;
+
+ comp_ring_cons = RCQ_BD(sw_comp_cons);
+ cqe = &fp->rx_comp_ring[comp_ring_cons];
+ cqe_fp = &cqe->fast_path_cqe;
} /* while */
fp->rx_bd_cons = bd_cons;
@@ -1053,8 +1051,6 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie)
#endif
/* Handle Rx and Tx according to MSI-X vector */
- prefetch(fp->rx_cons_sb);
-
for_each_cos_in_tx_queue(fp, cos)
prefetch(fp->txdata_ptr[cos]->tx_cons_sb);
@@ -1118,7 +1114,7 @@ static void bnx2x_fill_report_data(struct bnx2x *bp,
memset(data, 0, sizeof(*data));
- /* Fill the report data: efective line speed */
+ /* Fill the report data: effective line speed */
data->line_speed = line_speed;
/* Link is down */
@@ -1161,7 +1157,7 @@ void bnx2x_link_report(struct bnx2x *bp)
*
* @bp: driver handle
*
- * None atomic inmlementation.
+ * None atomic implementation.
* Should be called under the phy_lock.
*/
void __bnx2x_link_report(struct bnx2x *bp)
@@ -1304,7 +1300,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
"mtu %d rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size);
if (!fp->disable_tpa) {
- /* Fill the per-aggregtion pool */
+ /* Fill the per-aggregation pool */
for (i = 0; i < MAX_AGG_QS(bp); i++) {
struct bnx2x_agg_info *tpa_info =
&fp->tpa_info[i];
@@ -1759,32 +1755,46 @@ static void bnx2x_napi_enable_cnic(struct bnx2x *bp)
{
int i;
- for_each_rx_queue_cnic(bp, i)
+ for_each_rx_queue_cnic(bp, i) {
+ bnx2x_fp_init_lock(&bp->fp[i]);
napi_enable(&bnx2x_fp(bp, i, napi));
+ }
}
static void bnx2x_napi_enable(struct bnx2x *bp)
{
int i;
- for_each_eth_queue(bp, i)
+ for_each_eth_queue(bp, i) {
+ bnx2x_fp_init_lock(&bp->fp[i]);
napi_enable(&bnx2x_fp(bp, i, napi));
+ }
}
static void bnx2x_napi_disable_cnic(struct bnx2x *bp)
{
int i;
- for_each_rx_queue_cnic(bp, i)
+ local_bh_disable();
+ for_each_rx_queue_cnic(bp, i) {
napi_disable(&bnx2x_fp(bp, i, napi));
+ while (!bnx2x_fp_lock_napi(&bp->fp[i]))
+ mdelay(1);
+ }
+ local_bh_enable();
}
static void bnx2x_napi_disable(struct bnx2x *bp)
{
int i;
- for_each_eth_queue(bp, i)
+ local_bh_disable();
+ for_each_eth_queue(bp, i) {
napi_disable(&bnx2x_fp(bp, i, napi));
+ while (!bnx2x_fp_lock_napi(&bp->fp[i]))
+ mdelay(1);
+ }
+ local_bh_enable();
}
void bnx2x_netif_start(struct bnx2x *bp)
@@ -1829,7 +1839,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb)
}
/* select a non-FCoE queue */
- return __skb_tx_hash(dev, skb, BNX2X_NUM_ETH_QUEUES(bp));
+ return __netdev_pick_tx(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
}
void bnx2x_set_num_queues(struct bnx2x *bp)
@@ -1862,7 +1872,7 @@ void bnx2x_set_num_queues(struct bnx2x *bp)
*
* If the actual number of Tx queues (for each CoS) is less than 16 then there
* will be the holes at the end of each group of 16 ETh L2 indices (0..15,
- * 16..31,...) with indicies that are not coupled with any real Tx queue.
+ * 16..31,...) with indices that are not coupled with any real Tx queue.
*
* The proper configuration of skb->queue_mapping is handled by
* bnx2x_select_queue() and __skb_tx_hash().
@@ -1924,7 +1934,7 @@ static void bnx2x_set_rx_buf_size(struct bnx2x *bp)
ETH_OVREHEAD +
mtu +
BNX2X_FW_RX_ALIGN_END;
- /* Note : rx_buf_size doesnt take into account NET_SKB_PAD */
+ /* Note : rx_buf_size doesn't take into account NET_SKB_PAD */
if (fp->rx_buf_size + NET_SKB_PAD <= PAGE_SIZE)
fp->rx_frag_size = fp->rx_buf_size + NET_SKB_PAD;
else
@@ -1937,7 +1947,7 @@ static int bnx2x_init_rss_pf(struct bnx2x *bp)
int i;
u8 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp);
- /* Prepare the initial contents fo the indirection table if RSS is
+ /* Prepare the initial contents for the indirection table if RSS is
* enabled
*/
for (i = 0; i < sizeof(bp->rss_conf_obj.ind_table); i++)
@@ -2015,7 +2025,7 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
/*
* Cleans the object that have internal lists without sending
- * ramrods. Should be run when interrutps are disabled.
+ * ramrods. Should be run when interrupts are disabled.
*/
void bnx2x_squeeze_objects(struct bnx2x *bp)
{
@@ -2166,10 +2176,10 @@ static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
bp->fw_stats_data_mapping = bp->fw_stats_mapping +
bp->fw_stats_req_sz;
- DP(BNX2X_MSG_SP, "statistics request base address set to %x %x",
+ DP(BNX2X_MSG_SP, "statistics request base address set to %x %x\n",
U64_HI(bp->fw_stats_req_mapping),
U64_LO(bp->fw_stats_req_mapping));
- DP(BNX2X_MSG_SP, "statistics data base address set to %x %x",
+ DP(BNX2X_MSG_SP, "statistics data base address set to %x %x\n",
U64_HI(bp->fw_stats_data_mapping),
U64_LO(bp->fw_stats_data_mapping));
return 0;
@@ -2183,6 +2193,8 @@ alloc_mem_err:
/* send load request to mcp and analyze response */
static int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
{
+ u32 param;
+
/* init fw_seq */
bp->fw_seq =
(SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
@@ -2195,9 +2207,13 @@ static int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code)
DRV_PULSE_SEQ_MASK);
BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq);
+ param = DRV_MSG_CODE_LOAD_REQ_WITH_LFA;
+
+ if (IS_MF_SD(bp) && bnx2x_port_after_undi(bp))
+ param |= DRV_MSG_CODE_LOAD_REQ_FORCE_LFA;
+
/* load request */
- (*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ,
- DRV_MSG_CODE_LOAD_REQ_WITH_LFA);
+ (*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ, param);
/* if mcp fails to respond we must abort */
if (!(*load_code)) {
@@ -2238,7 +2254,7 @@ int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code)
/* abort nic load if version mismatch */
if (my_fw != loaded_fw) {
- BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. aborting\n",
+ BNX2X_ERR("bnx2x with FW %x was already loaded which mismatches my %x FW. Aborting\n",
loaded_fw, my_fw);
return -EBUSY;
}
@@ -2316,10 +2332,10 @@ static void bnx2x_nic_load_afex_dcc(struct bnx2x *bp, int load_code)
static void bnx2x_bz_fp(struct bnx2x *bp, int index)
{
struct bnx2x_fastpath *fp = &bp->fp[index];
-
int cos;
struct napi_struct orig_napi = fp->napi;
struct bnx2x_agg_info *orig_tpa_info = fp->tpa_info;
+
/* bzero bnx2x_fastpath contents */
if (fp->tpa_info)
memset(fp->tpa_info, 0, ETH_MAX_AGGREGATION_QUEUES_E1H_E2 *
@@ -2345,8 +2361,7 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index)
fp->txdata_ptr[cos] = &bp->bnx2x_txq[cos *
BNX2X_NUM_ETH_QUEUES(bp) + index];
- /*
- * set the tpa flag for each queue. The tpa flag determines the queue
+ /* set the tpa flag for each queue. The tpa flag determines the queue
* minimal size so it must be set prior to queue memory allocation
*/
fp->disable_tpa = !(bp->flags & TPA_ENABLE_FLAG ||
@@ -2429,7 +2444,6 @@ int bnx2x_load_cnic(struct bnx2x *bp)
if (bp->state == BNX2X_STATE_OPEN)
bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
-
DP(NETIF_MSG_IFUP, "Ending successfully CNIC-related load\n");
return 0;
@@ -2472,6 +2486,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
+ /* zero the structure w/o any lock, before SP handler is initialized */
memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link));
__set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
&bp->last_reported_link.link_report_flags);
@@ -2536,8 +2551,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
/* configure multi cos mappings in kernel.
- * this configuration may be overriden by a multi class queue discipline
- * or by a dcbx negotiation result.
+ * this configuration may be overridden by a multi class queue
+ * discipline or by a dcbx negotiation result.
*/
bnx2x_setup_tc(bp->dev, bp->max_cos);
@@ -2696,7 +2711,7 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* Start the Tx */
switch (load_mode) {
case LOAD_NORMAL:
- /* Tx queue should be only reenabled */
+ /* Tx queue should be only re-enabled */
netif_tx_wake_all_queues(bp->dev);
break;
@@ -2841,7 +2856,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
}
/* Nothing to do during unload if previous bnx2x_nic_load()
- * have not completed succesfully - all resourses are released.
+ * have not completed successfully - all resources are released.
*
* we can get here only after unsuccessful ndo_* callback, during which
* dev->IFF_UP flag is still on.
@@ -2890,10 +2905,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
/* Send the UNLOAD_REQUEST to the MCP */
bnx2x_send_unload_req(bp, unload_mode);
- /*
- * Prevent transactions to host from the functions on the
+ /* Prevent transactions to host from the functions on the
* engine that doesn't reset global blocks in case of global
- * attention once gloabl blocks are reset and gates are opened
+ * attention once global blocks are reset and gates are opened
* (the engine which leader will perform the recovery
* last).
*/
@@ -2914,7 +2928,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
}
/*
- * At this stage no more interrupts will arrive so we may safly clean
+ * At this stage no more interrupts will arrive so we may safely clean
* the queueable objects here in case they failed to get cleaned so far.
*/
if (IS_PF(bp))
@@ -2955,7 +2969,6 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
bnx2x_set_reset_global(bp);
}
-
/* The last driver must disable a "close the gate" if there is no
* parity attention or "process kill" pending.
*/
@@ -3040,6 +3053,8 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
return 0;
}
#endif
+ if (!bnx2x_fp_lock_napi(fp))
+ return work_done;
for_each_cos_in_tx_queue(fp, cos)
if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos]))
@@ -3049,12 +3064,15 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
work_done += bnx2x_rx_int(fp, budget - work_done);
/* must not complete if we consumed full budget */
- if (work_done >= budget)
+ if (work_done >= budget) {
+ bnx2x_fp_unlock_napi(fp);
break;
+ }
}
/* Fall out from the NAPI loop if needed */
- if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
+ if (!bnx2x_fp_unlock_napi(fp) &&
+ !(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) {
/* No need to update SB for FCoE L2 ring as long as
* it's connected to the default SB and the SB
@@ -3096,6 +3114,32 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
return work_done;
}
+#ifdef CONFIG_NET_LL_RX_POLL
+/* must be called with local_bh_disable()d */
+int bnx2x_low_latency_recv(struct napi_struct *napi)
+{
+ struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath,
+ napi);
+ struct bnx2x *bp = fp->bp;
+ int found = 0;
+
+ if ((bp->state == BNX2X_STATE_CLOSED) ||
+ (bp->state == BNX2X_STATE_ERROR) ||
+ (bp->flags & (TPA_ENABLE_FLAG | GRO_ENABLE_FLAG)))
+ return LL_FLUSH_FAILED;
+
+ if (!bnx2x_fp_lock_poll(fp))
+ return LL_FLUSH_BUSY;
+
+ if (bnx2x_has_rx_work(fp))
+ found = bnx2x_rx_int(fp, 4);
+
+ bnx2x_fp_unlock_poll(fp);
+
+ return found;
+}
+#endif
+
/* we split the first BD into headers and data BDs
* to ease the pain of our fellow microcode engineers
* we use one mapping for both BDs
@@ -3192,11 +3236,11 @@ static u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
rc |= XMIT_CSUM_TCP;
if (skb_is_gso_v6(skb)) {
- rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6);
+ rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP);
if (rc & XMIT_CSUM_ENC)
rc |= XMIT_GSO_ENC_V6;
} else if (skb_is_gso(skb)) {
- rc |= (XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP);
+ rc |= (XMIT_GSO_V4 | XMIT_CSUM_TCP);
if (rc & XMIT_CSUM_ENC)
rc |= XMIT_GSO_ENC_V4;
}
@@ -3313,6 +3357,7 @@ static void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
*/
static void bnx2x_set_pbd_gso(struct sk_buff *skb,
struct eth_tx_parse_bd_e1x *pbd,
+ struct eth_tx_start_bd *tx_start_bd,
u32 xmit_type)
{
pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
@@ -3326,11 +3371,14 @@ static void bnx2x_set_pbd_gso(struct sk_buff *skb,
ip_hdr(skb)->daddr,
0, IPPROTO_TCP, 0));
- } else
+ /* GSO on 57710/57711 needs FW to calculate IP checksum */
+ tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM;
+ } else {
pbd->tcp_pseudo_csum =
bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
&ipv6_hdr(skb)->daddr,
0, IPPROTO_TCP, 0));
+ }
pbd->global_data |=
cpu_to_le16(ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN);
@@ -3479,19 +3527,18 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb,
{
u16 hlen_w = 0;
u8 outerip_off, outerip_len = 0;
+
/* from outer IP to transport */
hlen_w = (skb_inner_transport_header(skb) -
skb_network_header(skb)) >> 1;
/* transport len */
- if (xmit_type & XMIT_CSUM_TCP)
- hlen_w += inner_tcp_hdrlen(skb) >> 1;
- else
- hlen_w += sizeof(struct udphdr) >> 1;
+ hlen_w += inner_tcp_hdrlen(skb) >> 1;
pbd2->fw_ip_hdr_to_payload_w = hlen_w;
- if (xmit_type & XMIT_CSUM_ENC_V4) {
+ /* outer IP header info */
+ if (xmit_type & XMIT_CSUM_V4) {
struct iphdr *iph = ip_hdr(skb);
pbd2->fw_ip_csum_wo_len_flags_frag =
bswab16(csum_fold((~iph->check) -
@@ -3583,7 +3630,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
DP(NETIF_MSG_TX_QUEUED, "indices: txq %d, fp %d, txdata %d\n",
txq_index, fp_index, txdata_index); */
- /* enable this debug print to view the tranmission details
+ /* enable this debug print to view the transmission details
DP(NETIF_MSG_TX_QUEUED,
"transmitting packet cid %d fp index %d txdata_index %d tx_data ptr %p fp pointer %p\n",
txdata->cid, fp_index, txdata_index, txdata, fp); */
@@ -3814,7 +3861,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
xmit_type);
else
- bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
+ bnx2x_set_pbd_gso(skb, pbd_e1x, first_bd, xmit_type);
}
/* Set the PBD's parsing_data field if not zero
@@ -3965,7 +4012,7 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
/* setup tc must be called under rtnl lock */
ASSERT_RTNL();
- /* no traffic classes requested. aborting */
+ /* no traffic classes requested. Aborting */
if (!num_tc) {
netdev_reset_tc(dev);
return 0;
@@ -3973,7 +4020,7 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
/* requested to support too many traffic classes */
if (num_tc > bp->max_cos) {
- BNX2X_ERR("support for too many traffic classes requested: %d. max supported is %d\n",
+ BNX2X_ERR("support for too many traffic classes requested: %d. Max supported is %d\n",
num_tc, bp->max_cos);
return -EINVAL;
}
@@ -3992,8 +4039,7 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
prio, bp->prio_to_cos[prio]);
}
-
- /* Use this configuration to diffrentiate tc0 from other COSes
+ /* Use this configuration to differentiate tc0 from other COSes
This can be used for ets or pfc, and save the effort of setting
up a multio class queue disc or negotiating DCBX with a switch
netdev_set_prio_tc_map(dev, 0, 0);
@@ -4285,10 +4331,11 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
&bnx2x_fp(bp, index, rx_desc_mapping),
sizeof(struct eth_rx_bd) * NUM_RX_BD);
- BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_comp_ring),
- &bnx2x_fp(bp, index, rx_comp_mapping),
- sizeof(struct eth_fast_path_rx_cqe) *
- NUM_RCQ_BD);
+ /* Seed all CQEs by 1s */
+ BNX2X_PCI_FALLOC(bnx2x_fp(bp, index, rx_comp_ring),
+ &bnx2x_fp(bp, index, rx_comp_mapping),
+ sizeof(struct eth_fast_path_rx_cqe) *
+ NUM_RCQ_BD);
/* SGE ring */
BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring),
@@ -4469,7 +4516,6 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp)
alloc_err:
bnx2x_free_mem_bp(bp);
return -ENOMEM;
-
}
int bnx2x_reload_if_running(struct net_device *dev)
@@ -4511,7 +4557,6 @@ int bnx2x_get_cur_phy_idx(struct bnx2x *bp)
}
return sel_phy_idx;
-
}
int bnx2x_get_link_cfg_idx(struct bnx2x *bp)
{
@@ -4599,6 +4644,7 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
{
struct bnx2x *bp = netdev_priv(dev);
u32 flags = bp->flags;
+ u32 changes;
bool bnx2x_reload = false;
if (features & NETIF_F_LRO)
@@ -4623,10 +4669,16 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features)
}
}
- if (flags ^ bp->flags) {
- bp->flags = flags;
+ changes = flags ^ bp->flags;
+
+ /* if GRO is changed while LRO is enabled, don't force a reload */
+ if ((changes & GRO_ENABLE_FLAG) && (flags & TPA_ENABLE_FLAG))
+ changes &= ~GRO_ENABLE_FLAG;
+
+ if (changes)
bnx2x_reload = true;
- }
+
+ bp->flags = flags;
if (bnx2x_reload) {
if (bp->recovery_state == BNX2X_RECOVERY_DONE)
@@ -4721,7 +4773,6 @@ int bnx2x_resume(struct pci_dev *pdev)
return rc;
}
-
void bnx2x_set_ctx_validation(struct bnx2x *bp, struct eth_context *cxt,
u32 cid)
{
@@ -4739,7 +4790,6 @@ static void storm_memset_hc_timeout(struct bnx2x *bp, u8 port,
u8 fw_sb_id, u8 sb_index,
u8 ticks)
{
-
u32 addr = BAR_CSTRORM_INTMEM +
CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(fw_sb_id, sb_index);
REG_WR8(bp, addr, ticks);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 151675d..c07a6d0 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -22,7 +22,6 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-
#include "bnx2x.h"
#include "bnx2x_sriov.h"
@@ -50,13 +49,25 @@ extern int int_mode;
} \
} while (0)
-#define BNX2X_PCI_ALLOC(x, y, size) \
-do { \
- x = dma_alloc_coherent(&bp->pdev->dev, size, y, \
- GFP_KERNEL | __GFP_ZERO); \
- if (x == NULL) \
- goto alloc_mem_err; \
-} while (0)
+#define BNX2X_PCI_ALLOC(x, y, size) \
+ do { \
+ x = dma_alloc_coherent(&bp->pdev->dev, size, y, \
+ GFP_KERNEL | __GFP_ZERO); \
+ if (x == NULL) \
+ goto alloc_mem_err; \
+ DP(NETIF_MSG_HW, "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n", \
+ (unsigned long long)(*y), x); \
+ } while (0)
+
+#define BNX2X_PCI_FALLOC(x, y, size) \
+ do { \
+ x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
+ if (x == NULL) \
+ goto alloc_mem_err; \
+ memset((void *)x, 0xFFFFFFFF, size); \
+ DP(NETIF_MSG_HW, "BNX2X_PCI_FALLOC: Physical %Lx Virtual %p\n",\
+ (unsigned long long)(*y), x); \
+ } while (0)
#define BNX2X_ALLOC(x, size) \
do { \
@@ -494,9 +505,6 @@ void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value);
/* Error handling */
void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl);
-/* validate currect fw is loaded */
-bool bnx2x_test_firmware_version(struct bnx2x *bp, bool is_err);
-
/* dev_close main block */
int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link);
@@ -607,6 +615,13 @@ int bnx2x_enable_msi(struct bnx2x *bp);
int bnx2x_poll(struct napi_struct *napi, int budget);
/**
+ * bnx2x_low_latency_recv - LL callback
+ *
+ * @napi: napi structure
+ */
+int bnx2x_low_latency_recv(struct napi_struct *napi);
+
+/**
* bnx2x_alloc_mem_bp - allocate memories outsize main driver structure
*
* @bp: driver handle
@@ -800,16 +815,18 @@ static inline bool bnx2x_has_tx_work(struct bnx2x_fastpath *fp)
return false;
}
+#define BNX2X_IS_CQE_COMPLETED(cqe_fp) (cqe_fp->marker == 0x0)
+#define BNX2X_SEED_CQE(cqe_fp) (cqe_fp->marker = 0xFFFFFFFF)
static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
{
- u16 rx_cons_sb;
+ u16 cons;
+ union eth_rx_cqe *cqe;
+ struct eth_fast_path_rx_cqe *cqe_fp;
- /* Tell compiler that status block fields can change */
- barrier();
- rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
- if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
- rx_cons_sb++;
- return (fp->rx_comp_cons != rx_cons_sb);
+ cons = RCQ_BD(fp->rx_comp_cons);
+ cqe = &fp->rx_comp_ring[cons];
+ cqe_fp = &cqe->fast_path_cqe;
+ return BNX2X_IS_CQE_COMPLETED(cqe_fp);
}
/**
@@ -848,9 +865,11 @@ static inline void bnx2x_add_all_napi_cnic(struct bnx2x *bp)
int i;
/* Add NAPI objects */
- for_each_rx_queue_cnic(bp, i)
+ for_each_rx_queue_cnic(bp, i) {
netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
bnx2x_poll, NAPI_POLL_WEIGHT);
+ napi_hash_add(&bnx2x_fp(bp, i, napi));
+ }
}
static inline void bnx2x_add_all_napi(struct bnx2x *bp)
@@ -858,25 +877,31 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp)
int i;
/* Add NAPI objects */
- for_each_eth_queue(bp, i)
+ for_each_eth_queue(bp, i) {
netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
bnx2x_poll, NAPI_POLL_WEIGHT);
+ napi_hash_add(&bnx2x_fp(bp, i, napi));
+ }
}
static inline void bnx2x_del_all_napi_cnic(struct bnx2x *bp)
{
int i;
- for_each_rx_queue_cnic(bp, i)
+ for_each_rx_queue_cnic(bp, i) {
+ napi_hash_del(&bnx2x_fp(bp, i, napi));
netif_napi_del(&bnx2x_fp(bp, i, napi));
+ }
}
static inline void bnx2x_del_all_napi(struct bnx2x *bp)
{
int i;
- for_each_eth_queue(bp, i)
+ for_each_eth_queue(bp, i) {
+ napi_hash_del(&bnx2x_fp(bp, i, napi));
netif_napi_del(&bnx2x_fp(bp, i, napi));
+ }
}
int bnx2x_set_int_mode(struct bnx2x *bp);
@@ -1171,7 +1196,6 @@ static inline u8 bnx2x_cnic_eth_cl_id(struct bnx2x *bp, u8 cl_idx)
static inline u8 bnx2x_cnic_fw_sb_id(struct bnx2x *bp)
{
-
/* the 'first' id is allocated for the cnic */
return bp->base_fw_ndsb;
}
@@ -1181,7 +1205,6 @@ static inline u8 bnx2x_cnic_igu_sb_id(struct bnx2x *bp)
return bp->igu_base_sb;
}
-
static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
{
struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp);
@@ -1334,8 +1357,8 @@ static inline bool bnx2x_mtu_allows_gro(int mtu)
int fpp = SGE_PAGE_SIZE / (mtu - ETH_MAX_TPA_HEADER_SIZE);
/*
- * 1. number of frags should not grow above MAX_SKB_FRAGS
- * 2. frag must fit the page
+ * 1. Number of frags should not grow above MAX_SKB_FRAGS
+ * 2. Frag must fit the page
*/
return mtu <= SGE_PAGE_SIZE && (U_ETH_SGL_SIZE * fpp) <= MAX_SKB_FRAGS;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
index 4b077a7..0c94df4 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
@@ -253,7 +253,6 @@ static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp,
memset(&pg_help_data, 0, sizeof(struct pg_help_data));
-
if (GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR))
DP(BNX2X_MSG_DCB, "DCBX_LOCAL_ETS_ERROR\n");
@@ -298,7 +297,6 @@ static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp,
static void bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp,
struct dcbx_pfc_feature *pfc, u32 error)
{
-
if (GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR))
DP(BNX2X_MSG_DCB, "DCBX_LOCAL_PFC_ERROR\n");
@@ -367,7 +365,6 @@ static int bnx2x_dcbx_read_mib(struct bnx2x *bp,
struct lldp_remote_mib *remote_mib ;
struct lldp_local_mib *local_mib;
-
switch (read_mib_type) {
case DCBX_READ_LOCAL_MIB:
mib_size = sizeof(struct lldp_local_mib);
@@ -629,7 +626,6 @@ static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp)
return 0;
}
-
#ifdef BCM_DCBNL
static inline
u8 bnx2x_dcbx_dcbnl_app_up(struct dcbx_app_priority_entry *ent)
@@ -691,7 +687,7 @@ static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp)
}
/* setup tc must be called under rtnl lock, but we can't take it here
- * as we are handling an attetntion on a work queue which must be
+ * as we are handling an attention on a work queue which must be
* flushed at some rtnl-locked contexts (e.g. if down)
*/
if (!test_and_set_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state))
@@ -711,7 +707,7 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
*/
bnx2x_dcbnl_update_applist(bp, true);
- /* Read rmeote mib if dcbx is in the FW */
+ /* Read remote mib if dcbx is in the FW */
if (bnx2x_dcbx_read_shmem_remote_mib(bp))
return;
#endif
@@ -742,7 +738,7 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
bnx2x_dcbx_update_tc_mapping(bp);
/*
- * allow other funtions to update their netdevices
+ * allow other functions to update their netdevices
* accordingly
*/
if (IS_MF(bp))
@@ -864,7 +860,7 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
i, DCBX_PRI_PG_GET(af->ets.pri_pg_tbl, i));
}
- /*For IEEE admin_recommendation_bw_precentage
+ /*For IEEE admin_recommendation_bw_percentage
*For IEEE admin_recommendation_ets_pg */
af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap;
for (i = 0; i < DCBX_CONFIG_MAX_APP_PROTOCOL; i++) {
@@ -896,13 +892,11 @@ static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp,
}
af->app.default_pri = (u8)dp->admin_default_priority;
-
}
/* Write the data. */
bnx2x_write_data(bp, (u32 *)&admin_mib, offset,
sizeof(struct lldp_admin_mib));
-
}
void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled)
@@ -1076,7 +1070,7 @@ static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,
bool pg_found = false;
u32 i, traf_type, add_traf_type, add_pg;
u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority;
- struct pg_entry_help_data *data = help_data->data; /*shotcut*/
+ struct pg_entry_help_data *data = help_data->data; /*shortcut*/
/* Set to invalid */
for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++)
@@ -1172,7 +1166,8 @@ static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
DCBX_PG_BW_GET(ets->pg_bw_tbl, pg_entry));
else
/* If we join a group and one is strict
- * than the bw rulls */
+ * than the bw rules
+ */
cos_data->data[entry].strict =
BNX2X_DCBX_STRICT_COS_HIGHEST;
}
@@ -1181,7 +1176,6 @@ static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
BNX2X_ERR("dcbx error: Both groups must have priorities\n");
}
-
#ifndef POWER_OF_2
#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1))))
#endif
@@ -1284,7 +1278,7 @@ static void bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(struct bnx2x *bp,
} else {
/* If there are only pauseable priorities or
* only non-pauseable,* the lower priorities go
- * to the first queue and the higherpriorities go
+ * to the first queue and the higher priorities go
* to the second queue.
*/
cos_data->data[0].pausable =
@@ -1484,7 +1478,7 @@ static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
* queue and one priority goes to the second queue.
*
* We will join this two cases:
- * if one is BW limited it will go to the secoend queue
+ * if one is BW limited it will go to the second queue
* otherwise the last priority will get it
*/
@@ -1504,7 +1498,8 @@ static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
false == b_found_strict)
/* last entry will be handled separately
* If no priority is strict than last
- * enty goes to last queue.*/
+ * entry goes to last queue.
+ */
entry = 1;
cos_data->data[entry].pri_join_mask |=
pri_tested;
@@ -1516,7 +1511,8 @@ static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
b_found_strict = true;
cos_data->data[1].pri_join_mask |= pri_tested;
/* If we join a group and one is strict
- * than the bw rulls */
+ * than the bw rules
+ */
cos_data->data[1].strict =
BNX2X_DCBX_STRICT_COS_HIGHEST;
}
@@ -1524,7 +1520,6 @@ static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params(
}
}
-
static void bnx2x_dcbx_2cos_limit_cee_fill_cos_params(struct bnx2x *bp,
struct pg_help_data *help_data,
struct dcbx_ets_feature *ets,
@@ -1533,7 +1528,6 @@ static void bnx2x_dcbx_2cos_limit_cee_fill_cos_params(struct bnx2x *bp,
u32 pri_join_mask,
u8 num_of_dif_pri)
{
-
/* default E2 settings */
cos_data->num_of_cos = DCBX_COS_MAX_NUM_E2;
@@ -1629,7 +1623,6 @@ static u8 bnx2x_dcbx_cee_fill_strict_pri(struct bnx2x *bp,
u8 num_spread_of_entries,
u8 strict_app_pris)
{
-
if (bnx2x_dcbx_spread_strict_pri(bp, cos_data, entry,
num_spread_of_entries,
strict_app_pris)) {
@@ -1848,7 +1841,7 @@ static void bnx2x_dcbx_fw_struct(struct bnx2x *bp,
void bnx2x_dcbx_pmf_update(struct bnx2x *bp)
{
- /* if we need to syncronize DCBX result from prev PMF
+ /* if we need to synchronize DCBX result from prev PMF
* read it from shmem and update bp and netdev accordingly
*/
if (SHMEM2_HAS(bp, drv_flags) &&
@@ -1876,7 +1869,6 @@ void bnx2x_dcbx_pmf_update(struct bnx2x *bp)
* dcbx negotiation.
*/
bnx2x_dcbx_update_tc_mapping(bp);
-
}
}
@@ -1943,14 +1935,14 @@ static void bnx2x_dcbnl_set_pg_tccfg_tx(struct net_device *netdev, int prio,
return;
/**
- * bw_pct ingnored - band-width percentage devision between user
+ * bw_pct ignored - band-width percentage devision between user
* priorities within the same group is not
* standard and hence not supported
*
- * prio_type igonred - priority levels within the same group are not
+ * prio_type ignored - priority levels within the same group are not
* standard and hence are not supported. According
* to the standard pgid 15 is dedicated to strict
- * prioirty traffic (on the port level).
+ * priority traffic (on the port level).
*
* up_map ignored
*/
@@ -1995,14 +1987,14 @@ static void bnx2x_dcbnl_get_pg_tccfg_tx(struct net_device *netdev, int prio,
DP(BNX2X_MSG_DCB, "prio = %d\n", prio);
/**
- * bw_pct ingnored - band-width percentage devision between user
+ * bw_pct ignored - band-width percentage devision between user
* priorities within the same group is not
* standard and hence not supported
*
- * prio_type igonred - priority levels within the same group are not
+ * prio_type ignored - priority levels within the same group are not
* standard and hence are not supported. According
* to the standard pgid 15 is dedicated to strict
- * prioirty traffic (on the port level).
+ * priority traffic (on the port level).
*
* up_map ignored
*/
@@ -2389,7 +2381,7 @@ static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,
*flags |= DCB_FEATCFG_ERROR;
break;
default:
- BNX2X_ERR("Non valid featrue-ID\n");
+ BNX2X_ERR("Non valid feature-ID\n");
rval = 1;
break;
}
@@ -2430,7 +2422,7 @@ static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid,
flags & DCB_FEATCFG_WILLING ? 1 : 0;
break;
default:
- BNX2X_ERR("Non valid featrue-ID\n");
+ BNX2X_ERR("Non valid feature-ID\n");
rval = 1;
break;
}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
index d153f44..125bd1b 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h
@@ -134,8 +134,6 @@ enum {
#define PFC_BRB1_REG_HIGH_LLFC_LOW_THRESHOLD 130
#define PFC_BRB1_REG_HIGH_LLFC_HIGH_THRESHOLD 170
-
-
struct cos_entry_help_data {
u32 pri_join_mask;
u32 cos_bw;
@@ -170,7 +168,6 @@ struct cos_help_data {
(!(IS_DCBX_PFC_PRI_ONLY_NON_PAUSE((bp), (pg_pri)) || \
IS_DCBX_PFC_PRI_ONLY_PAUSE((bp), (pg_pri))))
-
struct pg_entry_help_data {
u8 num_of_dif_pri;
u8 pg;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
index bff5e33..12eb4ba 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h
@@ -13,12 +13,6 @@
* consent.
*/
-
-/* This struct holds a signature to ensure the dump returned from the driver
- * match the meta data file inserted to grc_dump.tcl
- * The signature is time stamp, diag version and grc_dump version
- */
-
#ifndef BNX2X_DUMP_H
#define BNX2X_DUMP_H
@@ -28,7 +22,6 @@
#define DRV_DUMP_USTORM_WAITP_ADDRESS 0x338a80
#define DRV_DUMP_CSTORM_WAITP_ADDRESS 0x238a80
-
/* Possible Chips */
#define DUMP_CHIP_E1 1
#define DUMP_CHIP_E1H 2
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index ce1a916..7c6faeb 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -320,7 +320,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
speed = ethtool_cmd_speed(cmd);
- /* If recieved a request for an unknown duplex, assume full*/
+ /* If received a request for an unknown duplex, assume full*/
if (cmd->duplex == DUPLEX_UNKNOWN)
cmd->duplex = DUPLEX_FULL;
@@ -733,7 +733,6 @@ static bool bnx2x_is_reg_in_chip(struct bnx2x *bp,
return false;
}
-
static bool bnx2x_is_wreg_in_chip(struct bnx2x *bp,
const struct wreg_addr *wreg_info)
{
@@ -850,7 +849,7 @@ static int __bnx2x_get_preset_regs(struct bnx2x *bp, u32 *p, u32 preset)
/* Paged registers are supported in E2 & E3 only */
if (CHIP_IS_E2(bp) || CHIP_IS_E3(bp)) {
- /* Read "paged" registes */
+ /* Read "paged" registers */
bnx2x_read_pages_regs(bp, p, preset);
}
@@ -1155,8 +1154,8 @@ static int bnx2x_get_eeprom_len(struct net_device *dev)
return bp->common.flash_size;
}
-/* Per pf misc lock must be aquired before the per port mcp lock. Otherwise, had
- * we done things the other way around, if two pfs from the same port would
+/* Per pf misc lock must be acquired before the per port mcp lock. Otherwise,
+ * had we done things the other way around, if two pfs from the same port would
* attempt to access nvram at the same time, we could run into a scenario such
* as:
* pf A takes the port lock.
@@ -1381,12 +1380,29 @@ static int bnx2x_nvram_read32(struct bnx2x *bp, u32 offset, u32 *buf,
return rc;
}
+static bool bnx2x_is_nvm_accessible(struct bnx2x *bp)
+{
+ int rc = 1;
+ u16 pm = 0;
+ struct net_device *dev = pci_get_drvdata(bp->pdev);
+
+ if (bp->pm_cap)
+ rc = pci_read_config_word(bp->pdev,
+ bp->pm_cap + PCI_PM_CTRL, &pm);
+
+ if ((rc && !netif_running(dev)) ||
+ (!rc && ((pm & PCI_PM_CTRL_STATE_MASK) != PCI_D0)))
+ return false;
+
+ return true;
+}
+
static int bnx2x_get_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 *eebuf)
{
struct bnx2x *bp = netdev_priv(dev);
- if (!netif_running(dev)) {
+ if (!bnx2x_is_nvm_accessible(bp)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"cannot access eeprom when the interface is down\n");
return -EAGAIN;
@@ -1411,7 +1427,7 @@ static int bnx2x_get_module_eeprom(struct net_device *dev,
u8 *user_data = data;
unsigned int start_addr = ee->offset, xfer_size = 0;
- if (!netif_running(dev)) {
+ if (!bnx2x_is_nvm_accessible(bp)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"cannot access eeprom when the interface is down\n");
return -EAGAIN;
@@ -1474,7 +1490,7 @@ static int bnx2x_get_module_info(struct net_device *dev,
int phy_idx, rc;
u8 sff8472_comp, diag_type;
- if (!netif_running(dev)) {
+ if (!bnx2x_is_nvm_accessible(bp)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"cannot access eeprom when the interface is down\n");
return -EAGAIN;
@@ -1676,7 +1692,8 @@ static int bnx2x_set_eeprom(struct net_device *dev,
int port = BP_PORT(bp);
int rc = 0;
u32 ext_phy_config;
- if (!netif_running(dev)) {
+
+ if (!bnx2x_is_nvm_accessible(bp)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"cannot access eeprom when the interface is down\n");
return -EAGAIN;
@@ -1921,6 +1938,19 @@ static const char bnx2x_tests_str_arr[BNX2X_NUM_TESTS_SF][ETH_GSTRING_LEN] = {
"link_test (online) "
};
+enum {
+ BNX2X_PRI_FLAG_ISCSI,
+ BNX2X_PRI_FLAG_FCOE,
+ BNX2X_PRI_FLAG_STORAGE,
+ BNX2X_PRI_FLAG_LEN,
+};
+
+static const char bnx2x_private_arr[BNX2X_PRI_FLAG_LEN][ETH_GSTRING_LEN] = {
+ "iSCSI offload support",
+ "FCoE offload support",
+ "Storage only interface"
+};
+
static u32 bnx2x_eee_to_adv(u32 eee_adv)
{
u32 modes = 0;
@@ -2041,7 +2071,7 @@ static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata)
EEE_MODE_OVERRIDE_NVRAM |
EEE_MODE_OUTPUT_TIME;
- /* Restart link to propogate changes */
+ /* Restart link to propagate changes */
if (netif_running(dev)) {
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
bnx2x_force_link_reset(bp);
@@ -2160,7 +2190,7 @@ static int bnx2x_test_registers(struct bnx2x *bp)
{ BNX2X_CHIP_MASK_ALL, 0xffffffff, 0, 0x00000000 }
};
- if (!netif_running(bp->dev)) {
+ if (!bnx2x_is_nvm_accessible(bp)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"cannot access eeprom when the interface is down\n");
return rc;
@@ -2264,7 +2294,7 @@ static int bnx2x_test_memory(struct bnx2x *bp)
{ NULL, 0xffffffff, {0, 0, 0, 0} }
};
- if (!netif_running(bp->dev)) {
+ if (!bnx2x_is_nvm_accessible(bp)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"cannot access eeprom when the interface is down\n");
return rc;
@@ -2978,32 +3008,47 @@ static int bnx2x_num_stat_queues(struct bnx2x *bp)
static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
{
struct bnx2x *bp = netdev_priv(dev);
- int i, num_stats;
+ int i, num_strings = 0;
switch (stringset) {
case ETH_SS_STATS:
if (is_multi(bp)) {
- num_stats = bnx2x_num_stat_queues(bp) *
- BNX2X_NUM_Q_STATS;
+ num_strings = bnx2x_num_stat_queues(bp) *
+ BNX2X_NUM_Q_STATS;
} else
- num_stats = 0;
+ num_strings = 0;
if (IS_MF_MODE_STAT(bp)) {
for (i = 0; i < BNX2X_NUM_STATS; i++)
if (IS_FUNC_STAT(i))
- num_stats++;
+ num_strings++;
} else
- num_stats += BNX2X_NUM_STATS;
+ num_strings += BNX2X_NUM_STATS;
- return num_stats;
+ return num_strings;
case ETH_SS_TEST:
return BNX2X_NUM_TESTS(bp);
+ case ETH_SS_PRIV_FLAGS:
+ return BNX2X_PRI_FLAG_LEN;
+
default:
return -EINVAL;
}
}
+static u32 bnx2x_get_private_flags(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ u32 flags = 0;
+
+ flags |= (!(bp->flags & NO_ISCSI_FLAG) ? 1 : 0) << BNX2X_PRI_FLAG_ISCSI;
+ flags |= (!(bp->flags & NO_FCOE_FLAG) ? 1 : 0) << BNX2X_PRI_FLAG_FCOE;
+ flags |= (!!IS_MF_STORAGE_ONLY(bp)) << BNX2X_PRI_FLAG_STORAGE;
+
+ return flags;
+}
+
static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct bnx2x *bp = netdev_priv(dev);
@@ -3026,7 +3071,6 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
}
}
-
for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i))
continue;
@@ -3045,6 +3089,12 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
start = 4;
memcpy(buf, bnx2x_tests_str_arr + start,
ETH_GSTRING_LEN * BNX2X_NUM_TESTS(bp));
+ break;
+
+ case ETH_SS_PRIV_FLAGS:
+ memcpy(buf, bnx2x_private_arr,
+ ETH_GSTRING_LEN * BNX2X_PRI_FLAG_LEN);
+ break;
}
}
@@ -3106,17 +3156,12 @@ static int bnx2x_set_phys_id(struct net_device *dev,
{
struct bnx2x *bp = netdev_priv(dev);
- if (!netif_running(dev)) {
+ if (!bnx2x_is_nvm_accessible(bp)) {
DP(BNX2X_MSG_ETHTOOL | BNX2X_MSG_NVM,
"cannot access eeprom when the interface is down\n");
return -EAGAIN;
}
- if (!bp->port.pmf) {
- DP(BNX2X_MSG_ETHTOOL, "Interface is not pmf\n");
- return -EOPNOTSUPP;
- }
-
switch (state) {
case ETHTOOL_ID_ACTIVE:
return 1; /* cycle on/off once per second */
@@ -3148,7 +3193,6 @@ static int bnx2x_set_phys_id(struct net_device *dev,
static int bnx2x_get_rss_flags(struct bnx2x *bp, struct ethtool_rxnfc *info)
{
-
switch (info->flow_type) {
case TCP_V4_FLOW:
case TCP_V6_FLOW:
@@ -3384,7 +3428,6 @@ static int bnx2x_set_channels(struct net_device *dev,
{
struct bnx2x *bp = netdev_priv(dev);
-
DP(BNX2X_MSG_ETHTOOL,
"set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n",
channels->rx_count, channels->tx_count, channels->other_count,
@@ -3445,6 +3488,7 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
.set_pauseparam = bnx2x_set_pauseparam,
.self_test = bnx2x_self_test,
.get_sset_count = bnx2x_get_sset_count,
+ .get_priv_flags = bnx2x_get_private_flags,
.get_strings = bnx2x_get_strings,
.set_phys_id = bnx2x_set_phys_id,
.get_ethtool_stats = bnx2x_get_ethtool_stats,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
index 12f00a4..5018e52 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
@@ -1323,6 +1323,8 @@ struct drv_func_mb {
#define DRV_MSG_CODE_UNLOAD_SKIP_LINK_RESET 0x00000002
#define DRV_MSG_CODE_LOAD_REQ_WITH_LFA 0x0000100a
+ #define DRV_MSG_CODE_LOAD_REQ_FORCE_LFA 0x00002000
+
u32 fw_mb_header;
#define FW_MSG_CODE_MASK 0xffff0000
#define FW_MSG_CODE_DRV_LOAD_COMMON 0x10100000
@@ -3816,7 +3818,8 @@ struct eth_fast_path_rx_cqe {
__le16 len_on_bd;
struct parsing_flags pars_flags;
union eth_sgl_or_raw_data sgl_or_raw_data;
- __le32 reserved1[8];
+ __le32 reserved1[7];
+ u32 marker;
};
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index b4c9dea..c962d66 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -93,7 +93,6 @@ MODULE_FIRMWARE(FW_FILE_NAME_E1);
MODULE_FIRMWARE(FW_FILE_NAME_E1H);
MODULE_FIRMWARE(FW_FILE_NAME_E2);
-
int num_queues;
module_param(num_queues, int, 0);
MODULE_PARM_DESC(num_queues,
@@ -103,8 +102,6 @@ static int disable_tpa;
module_param(disable_tpa, int, 0);
MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
-#define INT_MODE_INTx 1
-#define INT_MODE_MSI 2
int int_mode;
module_param(int_mode, int, 0);
MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X "
@@ -122,8 +119,6 @@ static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, " Default debug msglevel");
-
-
struct workqueue_struct *bnx2x_wq;
struct bnx2x_mac_vals {
@@ -376,9 +371,11 @@ static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
#define DMAE_DP_DST_PCI "pci dst_addr [%x:%08x]"
#define DMAE_DP_DST_NONE "dst_addr [none]"
-void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl)
+static void bnx2x_dp_dmae(struct bnx2x *bp,
+ struct dmae_command *dmae, int msglvl)
{
u32 src_type = dmae->opcode & DMAE_COMMAND_SRC;
+ int i;
switch (dmae->opcode & DMAE_COMMAND_DST) {
case DMAE_CMD_DST_PCI:
@@ -434,6 +431,10 @@ void bnx2x_dp_dmae(struct bnx2x *bp, struct dmae_command *dmae, int msglvl)
dmae->comp_val);
break;
}
+
+ for (i = 0; i < (sizeof(struct dmae_command)/4); i++)
+ DP(msglvl, "DMAE RAW [%02d]: 0x%08x\n",
+ i, *(((u32 *)dmae) + i));
}
/* copy command into DMAE command memory and set DMAE command go */
@@ -508,8 +509,9 @@ int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae)
int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
int rc = 0;
- /*
- * Lock the dmae channel. Disable BHs to prevent a dead-lock
+ bnx2x_dp_dmae(bp, dmae, BNX2X_MSG_DMAE);
+
+ /* Lock the dmae channel. Disable BHs to prevent a dead-lock
* as long as this code is called both from syscall context and
* from ndo_set_rx_mode() flow that may be called from BH.
*/
@@ -548,6 +550,7 @@ unlock:
void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
u32 len32)
{
+ int rc;
struct dmae_command dmae;
if (!bp->dmae_ready) {
@@ -571,11 +574,16 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
dmae.len = len32;
/* issue the command and wait for completion */
- bnx2x_issue_dmae_with_comp(bp, &dmae);
+ rc = bnx2x_issue_dmae_with_comp(bp, &dmae);
+ if (rc) {
+ BNX2X_ERR("DMAE returned failure %d\n", rc);
+ bnx2x_panic();
+ }
}
void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
{
+ int rc;
struct dmae_command dmae;
if (!bp->dmae_ready) {
@@ -603,7 +611,11 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
dmae.len = len32;
/* issue the command and wait for completion */
- bnx2x_issue_dmae_with_comp(bp, &dmae);
+ rc = bnx2x_issue_dmae_with_comp(bp, &dmae);
+ if (rc) {
+ BNX2X_ERR("DMAE returned failure %d\n", rc);
+ bnx2x_panic();
+ };
}
static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
@@ -811,8 +823,8 @@ static void bnx2x_hc_int_disable(struct bnx2x *bp)
u32 val = REG_RD(bp, addr);
/* in E1 we must use only PCI configuration space to disable
- * MSI/MSIX capablility
- * It's forbitten to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
+ * MSI/MSIX capability
+ * It's forbidden to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
*/
if (CHIP_IS_E1(bp)) {
/* Since IGU_PF_CONF_MSI_MSIX_EN still always on
@@ -839,7 +851,7 @@ static void bnx2x_hc_int_disable(struct bnx2x *bp)
REG_WR(bp, addr, val);
if (REG_RD(bp, addr) != val)
- BNX2X_ERR("BUG! proper val not read from IGU!\n");
+ BNX2X_ERR("BUG! Proper val not read from IGU!\n");
}
static void bnx2x_igu_int_disable(struct bnx2x *bp)
@@ -857,7 +869,7 @@ static void bnx2x_igu_int_disable(struct bnx2x *bp)
REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
- BNX2X_ERR("BUG! proper val not read from IGU!\n");
+ BNX2X_ERR("BUG! Proper val not read from IGU!\n");
}
static void bnx2x_int_disable(struct bnx2x *bp)
@@ -917,7 +929,6 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
sp_sb_data.p_func.vf_valid,
sp_sb_data.state);
-
for_each_eth_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
int loop;
@@ -1016,7 +1027,7 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
hc_sm_p[j].timer_value);
}
- /* Indecies data */
+ /* Indices data */
for (j = 0; j < loop; j++) {
pr_cont("INDEX[%d] flags (0x%x) timeout (0x%x)\n", j,
hc_index_p[j].flags,
@@ -1027,6 +1038,7 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
#ifdef BNX2X_STOP_ON_ERROR
/* event queue */
+ BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod);
for (i = 0; i < NUM_EQ_DESC; i++) {
u32 *data = (u32 *)&bp->eq_ring[i].message.data;
@@ -1111,7 +1123,7 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
* bnx2x_pf_flr_clnup() is called during nic_load in the per function HW
* initialization.
*/
-#define FLR_WAIT_USEC 10000 /* 10 miliseconds */
+#define FLR_WAIT_USEC 10000 /* 10 milliseconds */
#define FLR_WAIT_INTERVAL 50 /* usec */
#define FLR_POLL_CNT (FLR_WAIT_USEC/FLR_WAIT_INTERVAL) /* 200 */
@@ -1290,7 +1302,6 @@ void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
for (i = 0; i < ARRAY_SIZE(cmd_regs); i++)
bnx2x_pbf_pN_cmd_flushed(bp, &cmd_regs[i], poll_count);
-
/* Verify the transmission buffers are flushed P0, P1, P4 */
for (i = 0; i < ARRAY_SIZE(buf_regs); i++)
bnx2x_pbf_pN_buf_flushed(bp, &buf_regs[i], poll_count);
@@ -1305,11 +1316,9 @@ void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
#define OP_GEN_AGG_VECT(index) \
(((index) << SDM_OP_GEN_AGG_VECT_IDX_SHIFT) & SDM_OP_GEN_AGG_VECT_IDX)
-
int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)
{
u32 op_gen_command = 0;
-
u32 comp_addr = BAR_CSTRORM_INTMEM +
CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func);
int ret = 0;
@@ -1334,7 +1343,7 @@ int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)
bnx2x_panic();
return 1;
}
- /* Zero completion for nxt FLR */
+ /* Zero completion for next FLR */
REG_WR(bp, comp_addr, 0);
return ret;
@@ -1352,7 +1361,6 @@ u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
*/
static int bnx2x_poll_hw_usage_counters(struct bnx2x *bp, u32 poll_cnt)
{
-
/* wait for CFC PF usage-counter to zero (includes all the VFs) */
if (bnx2x_flr_clnup_poll_hw_counter(bp,
CFC_REG_NUM_LCIDS_INSIDE_PF,
@@ -1360,7 +1368,6 @@ static int bnx2x_poll_hw_usage_counters(struct bnx2x *bp, u32 poll_cnt)
poll_cnt))
return 1;
-
/* Wait for DQ PF usage-counter to zero (until DQ cleanup) */
if (bnx2x_flr_clnup_poll_hw_counter(bp,
DORQ_REG_PF_USAGE_CNT,
@@ -1390,7 +1397,7 @@ static int bnx2x_poll_hw_usage_counters(struct bnx2x *bp, u32 poll_cnt)
/* Wait DMAE PF usage counter to zero */
if (bnx2x_flr_clnup_poll_hw_counter(bp,
dmae_reg_go_c[INIT_DMAE_C(bp)],
- "DMAE dommand register timed out",
+ "DMAE command register timed out",
poll_cnt))
return 1;
@@ -1770,7 +1777,7 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
break;
case (RAMROD_CMD_ID_ETH_TERMINATE):
- DP(BNX2X_MSG_SP, "got MULTI[%d] teminate ramrod\n", cid);
+ DP(BNX2X_MSG_SP, "got MULTI[%d] terminate ramrod\n", cid);
drv_cmd = BNX2X_Q_CMD_TERMINATE;
break;
@@ -1859,7 +1866,6 @@ irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
mask = 0x2 << (fp->index + CNIC_SUPPORT(bp));
if (status & mask) {
/* Handle Rx or Tx according to SB id */
- prefetch(fp->rx_cons_sb);
for_each_cos_in_tx_queue(fp, cos)
prefetch(fp->txdata_ptr[cos]->tx_cons_sb);
prefetch(&fp->sb_running_index[SM_RX_ID]);
@@ -1947,7 +1953,7 @@ int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
if (lock_status & resource_bit)
return 0;
- msleep(5);
+ usleep_range(5000, 10000);
}
BNX2X_ERR("Timeout\n");
return -EAGAIN;
@@ -1982,8 +1988,8 @@ int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
/* Validating that the resource is currently taken */
lock_status = REG_RD(bp, hw_lock_control_reg);
if (!(lock_status & resource_bit)) {
- BNX2X_ERR("lock_status 0x%x resource_bit 0x%x. unlock was called but lock wasn't taken!\n",
- lock_status, resource_bit);
+ BNX2X_ERR("lock_status 0x%x resource_bit 0x%x. Unlock was called but lock wasn't taken!\n",
+ lock_status, resource_bit);
return -EFAULT;
}
@@ -1991,7 +1997,6 @@ int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
return 0;
}
-
int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
{
/* The GPIO should be swapped if swap register is set and active */
@@ -2347,14 +2352,13 @@ u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes)
return rc;
}
-
/* Calculates the sum of vn_min_rates.
It's needed for further normalizing of the min_rates.
Returns:
sum of vn_min_rates.
or
0 - if all the min_rates are 0.
- In the later case fainess algorithm should be deactivated.
+ In the later case fairness algorithm should be deactivated.
If not all min_rates are zero then those that are zeroes will be set to 1.
*/
static void bnx2x_calc_vn_min(struct bnx2x *bp,
@@ -2419,7 +2423,6 @@ static void bnx2x_calc_vn_max(struct bnx2x *bp, int vn,
input->vnic_max_rate[vn] = vn_max_rate;
}
-
static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp)
{
if (CHIP_REV_IS_SLOW(bp))
@@ -2435,7 +2438,7 @@ void bnx2x_read_mf_cfg(struct bnx2x *bp)
int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1);
if (BP_NOMCP(bp))
- return; /* what should be the default bvalue in this case */
+ return; /* what should be the default value in this case */
/* For 2 port configuration the absolute function number formula
* is:
@@ -2901,7 +2904,6 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param)
return rc;
}
-
static void storm_memset_func_cfg(struct bnx2x *bp,
struct tstorm_eth_function_common_config *tcfg,
u16 abs_fid)
@@ -2935,7 +2937,7 @@ void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p)
}
/**
- * bnx2x_get_tx_only_flags - Return common flags
+ * bnx2x_get_common_flags - Return common flags
*
* @bp device handle
* @fp queue handle
@@ -3006,7 +3008,6 @@ static unsigned long bnx2x_get_q_flags(struct bnx2x *bp,
if (IS_MF_AFEX(bp))
__set_bit(BNX2X_Q_FLG_SILENT_VLAN_REM, &flags);
-
return flags | bnx2x_get_common_flags(bp, fp, true);
}
@@ -3082,7 +3083,7 @@ static void bnx2x_pf_rx_q_prep(struct bnx2x *bp,
* placed on the BD (not including paddings).
*/
rxq_init->buf_sz = fp->rx_buf_size - BNX2X_FW_RX_ALIGN_START -
- BNX2X_FW_RX_ALIGN_END - IP_HEADER_ALIGNMENT_PADDING;
+ BNX2X_FW_RX_ALIGN_END - IP_HEADER_ALIGNMENT_PADDING;
rxq_init->cl_qzone_id = fp->cl_qzone_id;
rxq_init->tpa_agg_sz = tpa_agg_size;
@@ -3124,7 +3125,7 @@ static void bnx2x_pf_tx_q_prep(struct bnx2x *bp,
txq_init->fw_sb_id = fp->fw_sb_id;
/*
- * set the tss leading client id for TX classfication ==
+ * set the tss leading client id for TX classification ==
* leading RSS client id
*/
txq_init->tss_leading_cl_id = bnx2x_fp(bp, 0, cl_id);
@@ -3196,7 +3197,6 @@ static void bnx2x_pf_init(struct bnx2x *bp)
storm_memset_eq_data(bp, &eq_data, BP_FUNC(bp));
}
-
static void bnx2x_e1h_disable(struct bnx2x *bp)
{
int port = BP_PORT(bp);
@@ -3212,7 +3212,7 @@ static void bnx2x_e1h_enable(struct bnx2x *bp)
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
- /* Tx queue should be only reenabled */
+ /* Tx queue should be only re-enabled */
netif_tx_wake_all_queues(bp->dev);
/*
@@ -3540,10 +3540,8 @@ static bool bnx2x_is_contextless_ramrod(int cmd, int cmd_type)
return true;
else
return false;
-
}
-
/**
* bnx2x_sp_post - place a single command on an SP ring
*
@@ -3608,14 +3606,13 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
/*
* It's ok if the actual decrement is issued towards the memory
* somewhere between the spin_lock and spin_unlock. Thus no
- * more explict memory barrier is needed.
+ * more explicit memory barrier is needed.
*/
if (common)
atomic_dec(&bp->eq_spq_left);
else
atomic_dec(&bp->cq_spq_left);
-
DP(BNX2X_MSG_SP,
"SPQE[%x] (%x:%x) (cmd, common?) (%d,%d) hw_cid %x data (%x:%x) type(0x%x) left (CQ, EQ) (%x,%x)\n",
bp->spq_prod_idx, (u32)U64_HI(bp->spq_mapping),
@@ -3637,15 +3634,14 @@ static int bnx2x_acquire_alr(struct bnx2x *bp)
might_sleep();
for (j = 0; j < 1000; j++) {
- val = (1UL << 31);
- REG_WR(bp, GRCBASE_MCP + 0x9c, val);
- val = REG_RD(bp, GRCBASE_MCP + 0x9c);
- if (val & (1L << 31))
+ REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, MCPR_ACCESS_LOCK_LOCK);
+ val = REG_RD(bp, MCP_REG_MCPR_ACCESS_LOCK);
+ if (val & MCPR_ACCESS_LOCK_LOCK)
break;
- msleep(5);
+ usleep_range(5000, 10000);
}
- if (!(val & (1L << 31))) {
+ if (!(val & MCPR_ACCESS_LOCK_LOCK)) {
BNX2X_ERR("Cannot acquire MCP access lock register\n");
rc = -EBUSY;
}
@@ -3656,7 +3652,7 @@ static int bnx2x_acquire_alr(struct bnx2x *bp)
/* release split MCP access lock register */
static void bnx2x_release_alr(struct bnx2x *bp)
{
- REG_WR(bp, GRCBASE_MCP + 0x9c, 0);
+ REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, 0);
}
#define BNX2X_DEF_SB_ATT_IDX 0x0001
@@ -3678,7 +3674,7 @@ static u16 bnx2x_update_dsb_idx(struct bnx2x *bp)
rc |= BNX2X_DEF_SB_IDX;
}
- /* Do not reorder: indecies reading should complete before handling */
+ /* Do not reorder: indices reading should complete before handling */
barrier();
return rc;
}
@@ -3827,8 +3823,7 @@ static void bnx2x_fan_failure(struct bnx2x *bp)
netdev_err(bp->dev, "Fan Failure on Network Controller has caused the driver to shutdown the card to prevent permanent damage.\n"
"Please contact OEM Support for assistance\n");
- /*
- * Schedule device reset (unload)
+ /* Schedule device reset (unload)
* This is due to some boards consuming sufficient power when driver is
* up to overheat if fan fails.
*/
@@ -3836,7 +3831,6 @@ static void bnx2x_fan_failure(struct bnx2x *bp)
set_bit(BNX2X_SP_RTNL_FAN_FAILURE, &bp->sp_rtnl_state);
smp_mb__after_clear_bit();
schedule_delayed_work(&bp->sp_rtnl_task, 0);
-
}
static void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
@@ -4106,7 +4100,7 @@ static void bnx2x_clear_reset_global(struct bnx2x *bp)
*/
static bool bnx2x_reset_is_global(struct bnx2x *bp)
{
- u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
+ u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
DP(NETIF_MSG_HW, "GEN_REG_VAL=0x%08x\n", val);
return (val & BNX2X_GLOBAL_RESET_BIT) ? true : false;
@@ -4157,7 +4151,7 @@ void bnx2x_set_reset_in_progress(struct bnx2x *bp)
*/
bool bnx2x_reset_is_done(struct bnx2x *bp, int engine)
{
- u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
+ u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
u32 bit = engine ?
BNX2X_PATH1_RST_IN_PROG_BIT : BNX2X_PATH0_RST_IN_PROG_BIT;
@@ -4260,13 +4254,18 @@ static bool bnx2x_get_load_status(struct bnx2x *bp, int engine)
return val != 0;
}
+static void _print_parity(struct bnx2x *bp, u32 reg)
+{
+ pr_cont(" [0x%08x] ", REG_RD(bp, reg));
+}
+
static void _print_next_block(int idx, const char *blk)
{
pr_cont("%s%s", idx ? ", " : "", blk);
}
-static int bnx2x_check_blocks_with_parity0(u32 sig, int par_num,
- bool print)
+static int bnx2x_check_blocks_with_parity0(struct bnx2x *bp, u32 sig,
+ int par_num, bool print)
{
int i = 0;
u32 cur_bit = 0;
@@ -4275,33 +4274,54 @@ static int bnx2x_check_blocks_with_parity0(u32 sig, int par_num,
if (sig & cur_bit) {
switch (cur_bit) {
case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "BRB");
+ _print_parity(bp,
+ BRB1_REG_BRB1_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "PARSER");
+ _print_parity(bp, PRS_REG_PRS_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "TSDM");
+ _print_parity(bp,
+ TSDM_REG_TSDM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++,
"SEARCHER");
+ _print_parity(bp, SRC_REG_SRC_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "TCM");
+ _print_parity(bp,
+ TCM_REG_TCM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "TSEMI");
+ _print_parity(bp,
+ TSEM_REG_TSEM_PRTY_STS_0);
+ _print_parity(bp,
+ TSEM_REG_TSEM_PRTY_STS_1);
+ }
break;
case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "XPB");
+ _print_parity(bp, GRCBASE_XPB +
+ PB_REG_PB_PRTY_STS);
+ }
break;
}
@@ -4313,8 +4333,9 @@ static int bnx2x_check_blocks_with_parity0(u32 sig, int par_num,
return par_num;
}
-static int bnx2x_check_blocks_with_parity1(u32 sig, int par_num,
- bool *global, bool print)
+static int bnx2x_check_blocks_with_parity1(struct bnx2x *bp, u32 sig,
+ int par_num, bool *global,
+ bool print)
{
int i = 0;
u32 cur_bit = 0;
@@ -4323,37 +4344,66 @@ static int bnx2x_check_blocks_with_parity1(u32 sig, int par_num,
if (sig & cur_bit) {
switch (cur_bit) {
case AEU_INPUTS_ATTN_BITS_PBF_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "PBF");
+ _print_parity(bp, PBF_REG_PBF_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "QM");
+ _print_parity(bp, QM_REG_QM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_TIMERS_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "TM");
+ _print_parity(bp, TM_REG_TM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "XSDM");
+ _print_parity(bp,
+ XSDM_REG_XSDM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_XCM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "XCM");
+ _print_parity(bp, XCM_REG_XCM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "XSEMI");
+ _print_parity(bp,
+ XSEM_REG_XSEM_PRTY_STS_0);
+ _print_parity(bp,
+ XSEM_REG_XSEM_PRTY_STS_1);
+ }
break;
case AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++,
"DOORBELLQ");
+ _print_parity(bp,
+ DORQ_REG_DORQ_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_NIG_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "NIG");
+ if (CHIP_IS_E1x(bp)) {
+ _print_parity(bp,
+ NIG_REG_NIG_PRTY_STS);
+ } else {
+ _print_parity(bp,
+ NIG_REG_NIG_PRTY_STS_0);
+ _print_parity(bp,
+ NIG_REG_NIG_PRTY_STS_1);
+ }
+ }
break;
case AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR:
if (print)
@@ -4362,32 +4412,52 @@ static int bnx2x_check_blocks_with_parity1(u32 sig, int par_num,
*global = true;
break;
case AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "DEBUG");
+ _print_parity(bp, DBG_REG_DBG_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "USDM");
+ _print_parity(bp,
+ USDM_REG_USDM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_UCM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "UCM");
+ _print_parity(bp, UCM_REG_UCM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "USEMI");
+ _print_parity(bp,
+ USEM_REG_USEM_PRTY_STS_0);
+ _print_parity(bp,
+ USEM_REG_USEM_PRTY_STS_1);
+ }
break;
case AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "UPB");
+ _print_parity(bp, GRCBASE_UPB +
+ PB_REG_PB_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "CSDM");
+ _print_parity(bp,
+ CSDM_REG_CSDM_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "CCM");
+ _print_parity(bp, CCM_REG_CCM_PRTY_STS);
+ }
break;
}
@@ -4399,8 +4469,8 @@ static int bnx2x_check_blocks_with_parity1(u32 sig, int par_num,
return par_num;
}
-static int bnx2x_check_blocks_with_parity2(u32 sig, int par_num,
- bool print)
+static int bnx2x_check_blocks_with_parity2(struct bnx2x *bp, u32 sig,
+ int par_num, bool print)
{
int i = 0;
u32 cur_bit = 0;
@@ -4409,12 +4479,23 @@ static int bnx2x_check_blocks_with_parity2(u32 sig, int par_num,
if (sig & cur_bit) {
switch (cur_bit) {
case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "CSEMI");
+ _print_parity(bp,
+ CSEM_REG_CSEM_PRTY_STS_0);
+ _print_parity(bp,
+ CSEM_REG_CSEM_PRTY_STS_1);
+ }
break;
case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "PXP");
+ _print_parity(bp, PXP_REG_PXP_PRTY_STS);
+ _print_parity(bp,
+ PXP2_REG_PXP2_PRTY_STS_0);
+ _print_parity(bp,
+ PXP2_REG_PXP2_PRTY_STS_1);
+ }
break;
case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR:
if (print)
@@ -4422,24 +4503,42 @@ static int bnx2x_check_blocks_with_parity2(u32 sig, int par_num,
"PXPPCICLOCKCLIENT");
break;
case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "CFC");
+ _print_parity(bp,
+ CFC_REG_CFC_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "CDU");
+ _print_parity(bp, CDU_REG_CDU_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_DMAE_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "DMAE");
+ _print_parity(bp,
+ DMAE_REG_DMAE_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "IGU");
+ if (CHIP_IS_E1x(bp))
+ _print_parity(bp,
+ HC_REG_HC_PRTY_STS);
+ else
+ _print_parity(bp,
+ IGU_REG_IGU_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "MISC");
+ _print_parity(bp,
+ MISC_REG_MISC_PRTY_STS);
+ }
break;
}
@@ -4493,8 +4592,8 @@ static int bnx2x_check_blocks_with_parity3(u32 sig, int par_num,
return par_num;
}
-static int bnx2x_check_blocks_with_parity4(u32 sig, int par_num,
- bool print)
+static int bnx2x_check_blocks_with_parity4(struct bnx2x *bp, u32 sig,
+ int par_num, bool print)
{
int i = 0;
u32 cur_bit = 0;
@@ -4503,12 +4602,18 @@ static int bnx2x_check_blocks_with_parity4(u32 sig, int par_num,
if (sig & cur_bit) {
switch (cur_bit) {
case AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "PGLUE_B");
+ _print_parity(bp,
+ PGLUE_B_REG_PGLUE_B_PRTY_STS);
+ }
break;
case AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR:
- if (print)
+ if (print) {
_print_next_block(par_num++, "ATC");
+ _print_parity(bp,
+ ATC_REG_ATC_PRTY_STS);
+ }
break;
}
@@ -4539,15 +4644,15 @@ static bool bnx2x_parity_attn(struct bnx2x *bp, bool *global, bool print,
if (print)
netdev_err(bp->dev,
"Parity errors detected in blocks: ");
- par_num = bnx2x_check_blocks_with_parity0(
+ par_num = bnx2x_check_blocks_with_parity0(bp,
sig[0] & HW_PRTY_ASSERT_SET_0, par_num, print);
- par_num = bnx2x_check_blocks_with_parity1(
+ par_num = bnx2x_check_blocks_with_parity1(bp,
sig[1] & HW_PRTY_ASSERT_SET_1, par_num, global, print);
- par_num = bnx2x_check_blocks_with_parity2(
+ par_num = bnx2x_check_blocks_with_parity2(bp,
sig[2] & HW_PRTY_ASSERT_SET_2, par_num, print);
par_num = bnx2x_check_blocks_with_parity3(
sig[3] & HW_PRTY_ASSERT_SET_3, par_num, global, print);
- par_num = bnx2x_check_blocks_with_parity4(
+ par_num = bnx2x_check_blocks_with_parity4(bp,
sig[4] & HW_PRTY_ASSERT_SET_4, par_num, print);
if (print)
@@ -4591,7 +4696,6 @@ bool bnx2x_chk_parity_attn(struct bnx2x *bp, bool *global, bool print)
return bnx2x_parity_attn(bp, global, print, attn.sig);
}
-
static void bnx2x_attn_int_deasserted4(struct bnx2x *bp, u32 attn)
{
u32 val;
@@ -4643,7 +4747,6 @@ static void bnx2x_attn_int_deasserted4(struct bnx2x *bp, u32 attn)
(u32)(attn & (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR |
AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR)));
}
-
}
static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted)
@@ -4878,7 +4981,6 @@ static void bnx2x_handle_classification_eqe(struct bnx2x *bp,
BNX2X_ERR("Failed to schedule new commands: %d\n", rc);
else if (rc > 0)
DP(BNX2X_MSG_SP, "Scheduled next pending commands...\n");
-
}
static void bnx2x_set_iscsi_eth_rx_mode(struct bnx2x *bp, bool start);
@@ -5009,7 +5111,7 @@ static void bnx2x_eq_int(struct bnx2x *bp)
hw_cons = le16_to_cpu(*bp->eq_cons_sb);
/* The hw_cos range is 1-255, 257 - the sw_cons range is 0-254, 256.
- * when we get the the next-page we nned to adjust so the loop
+ * when we get the next-page we need to adjust so the loop
* condition below will be met. The next element is the size of a
* regular element and hence incrementing by 1
*/
@@ -5075,8 +5177,6 @@ static void bnx2x_eq_int(struct bnx2x *bp)
if (q_obj->complete_cmd(bp, q_obj, BNX2X_Q_CMD_CFC_DEL))
break;
-
-
goto next_spqe;
case EVENT_RING_OPCODE_STOP_TRAFFIC:
@@ -5218,7 +5318,7 @@ static void bnx2x_sp_task(struct work_struct *work)
DP(BNX2X_MSG_SP, "sp task invoked\n");
- /* make sure the atomic interupt_occurred has been written */
+ /* make sure the atomic interrupt_occurred has been written */
smp_rmb();
if (atomic_read(&bp->interrupt_occurred)) {
@@ -5265,7 +5365,6 @@ static void bnx2x_sp_task(struct work_struct *work)
/* ack status block only if something was actually handled */
bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID,
le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
-
}
/* must be called after the EQ processing (since eq leads to sriov
@@ -5316,7 +5415,6 @@ irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
/* end of slow path */
-
void bnx2x_drv_pulse(struct bnx2x *bp)
{
SHMEM_WR(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb,
@@ -5382,7 +5480,6 @@ static void bnx2x_fill(struct bnx2x *bp, u32 addr, int fill, u32 len)
else
for (i = 0; i < len; i++)
REG_WR8(bp, addr + i, fill);
-
}
/* helper: writes FP SP data to FW - data_size in dwords */
@@ -5461,10 +5558,8 @@ static void bnx2x_zero_sp_sb(struct bnx2x *bp)
bnx2x_fill(bp, BAR_CSTRORM_INTMEM +
CSTORM_SP_SYNC_BLOCK_OFFSET(func), 0,
CSTORM_SP_SYNC_BLOCK_SIZE);
-
}
-
static void bnx2x_setup_ndsb_state_machine(struct hc_status_block_sm *hc_sm,
int igu_sb_id, int igu_seg_id)
{
@@ -5474,7 +5569,6 @@ static void bnx2x_setup_ndsb_state_machine(struct hc_status_block_sm *hc_sm,
hc_sm->time_to_expire = 0xFFFFFFFF;
}
-
/* allocates state machine ids. */
static void bnx2x_map_sb_state_machines(struct hc_index_data *index_data)
{
@@ -5700,7 +5794,7 @@ static void bnx2x_init_eq_ring(struct bnx2x *bp)
bp->eq_cons = 0;
bp->eq_prod = NUM_EQ_DESC;
bp->eq_cons_sb = BNX2X_EQ_INDEX;
- /* we want a warning message before it gets rought... */
+ /* we want a warning message before it gets wrought... */
atomic_set(&bp->eq_spq_left,
min_t(int, MAX_SP_DESC_CNT - MAX_SPQ_PENDING, NUM_EQ_DESC) - 1);
}
@@ -5784,7 +5878,7 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode,
break;
case BNX2X_RX_MODE_PROMISC:
- /* According to deffinition of SI mode, iface in promisc mode
+ /* According to definition of SI mode, iface in promisc mode
* should receive matched and unmatched (in resolution of port)
* unicast packets.
*/
@@ -5927,7 +6021,7 @@ static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx)
/* init shortcut */
fp->ustorm_rx_prods_offset = bnx2x_rx_ustorm_prods_offset(fp);
- /* Setup SB indicies */
+ /* Setup SB indices */
fp->rx_cons_sb = BNX2X_RX_SB_INDEX;
/* Configure Queue State object */
@@ -5983,6 +6077,8 @@ static void bnx2x_init_tx_ring_one(struct bnx2x_fp_txdata *txdata)
BCM_PAGE_SIZE*(i % NUM_TX_RINGS)));
}
+ *txdata->tx_cons_sb = cpu_to_le16(0);
+
SET_FLAG(txdata->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1);
txdata->tx_db.data.zero_fill1 = 0;
txdata->tx_db.data.prod = 0;
@@ -6001,6 +6097,7 @@ static void bnx2x_init_tx_rings_cnic(struct bnx2x *bp)
for_each_tx_queue_cnic(bp, i)
bnx2x_init_tx_ring_one(bp->fp[i].txdata_ptr[0]);
}
+
static void bnx2x_init_tx_rings(struct bnx2x *bp)
{
int i;
@@ -6043,11 +6140,6 @@ void bnx2x_pre_irq_nic_init(struct bnx2x *bp)
bnx2x_init_rx_rings(bp);
bnx2x_init_tx_rings(bp);
- if (IS_VF(bp)) {
- bnx2x_memset_stats(bp);
- return;
- }
-
if (IS_PF(bp)) {
/* Initialize MOD_ABS interrupts */
bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
@@ -6058,6 +6150,8 @@ void bnx2x_pre_irq_nic_init(struct bnx2x *bp)
bnx2x_init_def_sb(bp);
bnx2x_update_dsb_idx(bp);
bnx2x_init_sp_ring(bp);
+ } else {
+ bnx2x_memset_stats(bp);
}
}
@@ -6236,7 +6330,7 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
if (val == 0x10)
break;
- msleep(10);
+ usleep_range(10000, 20000);
count--;
}
if (val != 0x10) {
@@ -6251,7 +6345,7 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
if (val == 1)
break;
- msleep(10);
+ usleep_range(10000, 20000);
count--;
}
if (val != 0x1) {
@@ -6292,7 +6386,7 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
if (val == 0xb0)
break;
- msleep(10);
+ usleep_range(10000, 20000);
count--;
}
if (val != 0xb0) {
@@ -6681,7 +6775,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
* stay set)
* f. If this is VNIC 3 of a port then also init
* first_timers_ilt_entry to zero and last_timers_ilt_entry
- * to the last enrty in the ILT.
+ * to the last entry in the ILT.
*
* Notes:
* Currently the PF error in the PGLC is non recoverable.
@@ -6772,7 +6866,6 @@ static int bnx2x_init_hw_common(struct bnx2x *bp)
bnx2x_init_block(bp, BLOCK_QM, PHASE_COMMON);
-
/* QM queues pointers table */
bnx2x_qm_init_ptr_table(bp, bp->qm_cid_count, INITOP_SET);
@@ -7013,7 +7106,6 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
u32 low, high;
u32 val;
-
DP(NETIF_MSG_HW, "starting port init port %d\n", port);
REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0);
@@ -7078,7 +7170,6 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
BRB1_REG_MAC_GUARANTIED_1 :
BRB1_REG_MAC_GUARANTIED_0), 40);
-
bnx2x_init_block(bp, BLOCK_PRS, init_phase);
if (CHIP_IS_E3B0(bp)) {
if (IS_MF_AFEX(bp)) {
@@ -7150,8 +7241,8 @@ static int bnx2x_init_hw_port(struct bnx2x *bp)
bnx2x_init_block(bp, BLOCK_MISC_AEU, init_phase);
/* init aeu_mask_attn_func_0/1:
- * - SF mode: bits 3-7 are masked. only bits 0-2 are in use
- * - MF mode: bit 3 is masked. bits 0-2 are in use as in SF
+ * - SF mode: bits 3-7 are masked. Only bits 0-2 are in use
+ * - MF mode: bit 3 is masked. Bits 0-2 are in use as in SF
* bits 4-7 are used for "per vn group attention" */
val = IS_MF(bp) ? 0xF7 : 0x7;
/* Enable DCBX attention for all but E1 */
@@ -7275,7 +7366,6 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, bool is_pf)
while (!(REG_RD(bp, igu_addr_ack) & sb_bit) && --cnt)
msleep(20);
-
if (!(REG_RD(bp, igu_addr_ack) & sb_bit)) {
DP(NETIF_MSG_HW,
"Unable to finish IGU cleanup: idu_sb_id %d offset %d bit %d (cnt %d)\n",
@@ -7295,7 +7385,6 @@ static void bnx2x_clear_func_ilt(struct bnx2x *bp, u32 func)
bnx2x_ilt_wr(bp, i, 0);
}
-
static void bnx2x_init_searcher(struct bnx2x *bp)
{
int port = BP_PORT(bp);
@@ -7331,7 +7420,6 @@ static int bnx2x_reset_nic_mode(struct bnx2x *bp)
int rc, i, port = BP_PORT(bp);
int vlan_en = 0, mac_en[NUM_MACS];
-
/* Close input from network */
if (bp->mf_mode == SINGLE_FUNCTION) {
bnx2x_set_rx_filter(&bp->link_params, 0);
@@ -7406,7 +7494,7 @@ int bnx2x_init_hw_func_cnic(struct bnx2x *bp)
bnx2x_ilt_init_op_cnic(bp, INITOP_SET);
if (CONFIGURE_NIC_MODE(bp)) {
- /* Configrue searcher as part of function hw init */
+ /* Configure searcher as part of function hw init */
bnx2x_init_searcher(bp);
/* Reset NIC mode */
@@ -7479,8 +7567,7 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
} else {
/* Set NIC mode */
REG_WR(bp, PRS_REG_NIC_MODE, 1);
- DP(NETIF_MSG_IFUP, "NIC MODE configrued\n");
-
+ DP(NETIF_MSG_IFUP, "NIC MODE configured\n");
}
if (!CHIP_IS_E1x(bp)) {
@@ -7677,7 +7764,7 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
}
bnx2x_igu_clear_sb(bp, bp->igu_dsb_id);
- /* !!! these should become driver const once
+ /* !!! These should become driver const once
rf-tool supports split-68 const */
REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_LSB, 0);
REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_MSB, 0);
@@ -7734,7 +7821,6 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
return 0;
}
-
void bnx2x_free_mem_cnic(struct bnx2x *bp)
{
bnx2x_ilt_mem_op_cnic(bp, ILT_MEMOP_FREE);
@@ -7779,7 +7865,6 @@ void bnx2x_free_mem(struct bnx2x *bp)
bnx2x_iov_free_mem(bp);
}
-
int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
{
if (!CHIP_IS_E1x(bp))
@@ -7793,7 +7878,7 @@ int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
host_hc_status_block_e1x));
if (CONFIGURE_NIC_MODE(bp) && !bp->t2)
- /* allocate searcher T2 table, as it wan't allocated before */
+ /* allocate searcher T2 table, as it wasn't allocated before */
BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ);
/* write address to which L5 should insert its values */
@@ -8068,7 +8153,6 @@ void bnx2x_ilt_set_info(struct bnx2x *bp)
ilt_client->page_size,
ilt_client->flags,
ilog2(ilt_client->page_size >> 12));
-
}
if (CNIC_SUPPORT(bp)) {
@@ -8124,7 +8208,6 @@ void bnx2x_ilt_set_info(struct bnx2x *bp)
static void bnx2x_pf_q_prep_init(struct bnx2x *bp,
struct bnx2x_fastpath *fp, struct bnx2x_queue_init_params *init_params)
{
-
u8 cos;
int cxt_index, cxt_offset;
@@ -8133,7 +8216,7 @@ static void bnx2x_pf_q_prep_init(struct bnx2x *bp,
__set_bit(BNX2X_Q_FLG_HC, &init_params->rx.flags);
__set_bit(BNX2X_Q_FLG_HC, &init_params->tx.flags);
- /* If HC is supporterd, enable host coalescing in the transition
+ /* If HC is supported, enable host coalescing in the transition
* to INIT state.
*/
__set_bit(BNX2X_Q_FLG_HC_EN, &init_params->rx.flags);
@@ -8205,7 +8288,6 @@ static int bnx2x_setup_tx_only(struct bnx2x *bp, struct bnx2x_fastpath *fp,
return bnx2x_queue_state_change(bp, q_params);
}
-
/**
* bnx2x_setup_queue - setup queue
*
@@ -8254,7 +8336,6 @@ int bnx2x_setup_queue(struct bnx2x *bp, struct bnx2x_fastpath *fp,
DP(NETIF_MSG_IFUP, "init complete\n");
-
/* Now move the Queue to the SETUP state... */
memset(setup_params, 0, sizeof(*setup_params));
@@ -8315,7 +8396,6 @@ static int bnx2x_stop_queue(struct bnx2x *bp, int index)
/* We want to wait for completion in this context */
__set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
-
/* close tx-only connections */
for (tx_index = FIRST_TX_ONLY_COS_INDEX;
tx_index < fp->max_cos;
@@ -8369,7 +8449,6 @@ static int bnx2x_stop_queue(struct bnx2x *bp, int index)
return bnx2x_queue_state_change(bp, &q_params);
}
-
static void bnx2x_reset_func(struct bnx2x *bp)
{
int port = BP_PORT(bp);
@@ -8422,7 +8501,7 @@ static void bnx2x_reset_func(struct bnx2x *bp)
* scan to complete
*/
for (i = 0; i < 200; i++) {
- msleep(10);
+ usleep_range(10000, 20000);
if (!REG_RD(bp, TM_REG_LIN0_SCAN_ON + port*4))
break;
}
@@ -8623,14 +8702,14 @@ static int bnx2x_func_wait_started(struct bnx2x *bp)
/*
* (assumption: No Attention from MCP at this stage)
- * PMF probably in the middle of TXdisable/enable transaction
+ * PMF probably in the middle of TX disable/enable transaction
* 1. Sync IRS for default SB
- * 2. Sync SP queue - this guarantes us that attention handling started
- * 3. Wait, that TXdisable/enable transaction completes
+ * 2. Sync SP queue - this guarantees us that attention handling started
+ * 3. Wait, that TX disable/enable transaction completes
*
- * 1+2 guranty that if DCBx attention was scheduled it already changed
- * pending bit of transaction from STARTED-->TX_STOPPED, if we alredy
- * received complettion for the transaction the state is TX_STOPPED.
+ * 1+2 guarantee that if DCBx attention was scheduled it already changed
+ * pending bit of transaction from STARTED-->TX_STOPPED, if we already
+ * received completion for the transaction the state is TX_STOPPED.
* State will return to STARTED after completion of TX_STOPPED-->STARTED
* transaction.
*/
@@ -8660,7 +8739,7 @@ static int bnx2x_func_wait_started(struct bnx2x *bp)
struct bnx2x_func_state_params func_params = {NULL};
DP(NETIF_MSG_IFDOWN,
- "Hmmm... unexpected function state! Forcing STARTED-->TX_ST0PPED-->STARTED\n");
+ "Hmmm... Unexpected function state! Forcing STARTED-->TX_ST0PPED-->STARTED\n");
func_params.f_obj = &bp->func_obj;
__set_bit(RAMROD_DRV_CLR_ONLY,
@@ -8740,7 +8819,6 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
bnx2x_iov_chip_cleanup(bp);
-
/*
* Send the UNLOAD_REQUEST to the MCP. This will return if
* this function should perform FUNC, PORT or COMMON HW
@@ -8750,7 +8828,7 @@ void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode, bool keep_link)
/*
* (assumption: No Attention from MCP at this stage)
- * PMF probably in the middle of TXdisable/enable transaction
+ * PMF probably in the middle of TX disable/enable transaction
*/
rc = bnx2x_func_wait_started(bp);
if (rc) {
@@ -8813,7 +8891,6 @@ unload_error:
if (rc)
BNX2X_ERR("HW_RESET failed\n");
-
/* Report UNLOAD_DONE to MCP */
bnx2x_send_unload_done(bp, keep_link);
}
@@ -9179,7 +9256,6 @@ static int bnx2x_process_kill(struct bnx2x *bp, bool global)
if (!CHIP_IS_E1x(bp) && bnx2x_er_poll_igu_vq(bp))
return -EAGAIN;
-
/* TBD: Indicate that "process kill" is in progress to MCP */
/* Clear "unprepared" bit */
@@ -9367,7 +9443,7 @@ static void bnx2x_parity_recover(struct bnx2x *bp)
* the first leader that performs a
* leader_reset() reset the global blocks in
* order to clear global attentions. Otherwise
- * the the gates will remain closed for that
+ * the gates will remain closed for that
* engine.
*/
if (load_status ||
@@ -9480,14 +9556,12 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
return;
}
- /* if stop on error is defined no recovery flows should be executed */
+ if (unlikely(bp->recovery_state != BNX2X_RECOVERY_DONE)) {
#ifdef BNX2X_STOP_ON_ERROR
- BNX2X_ERR("recovery flow called but STOP_ON_ERROR defined so reset not done to allow debug dump,\n"
- "you will need to reboot when done\n");
- goto sp_rtnl_not_reset;
+ BNX2X_ERR("recovery flow called but STOP_ON_ERROR defined so reset not done to allow debug dump,\n"
+ "you will need to reboot when done\n");
+ goto sp_rtnl_not_reset;
#endif
-
- if (unlikely(bp->recovery_state != BNX2X_RECOVERY_DONE)) {
/*
* Clear all pending SP commands as we are going to reset the
* function anyway.
@@ -9502,6 +9576,12 @@ static void bnx2x_sp_rtnl_task(struct work_struct *work)
}
if (test_and_clear_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state)) {
+#ifdef BNX2X_STOP_ON_ERROR
+ BNX2X_ERR("recovery flow called but STOP_ON_ERROR defined so reset not done to allow debug dump,\n"
+ "you will need to reboot when done\n");
+ goto sp_rtnl_not_reset;
+#endif
+
/*
* Clear all pending SP commands as we are going to reset the
* function anyway.
@@ -9647,7 +9727,6 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE;
REG_WR(bp, vals->bmac_addr, wb_data[0]);
REG_WR(bp, vals->bmac_addr + 0x4, wb_data[1]);
-
}
BNX2X_DEV_INFO("Disable emac Rx\n");
vals->emac_addr = NIG_REG_NIG_EMAC0_EN + BP_PORT(bp)*4;
@@ -9681,7 +9760,6 @@ static void bnx2x_prev_unload_close_mac(struct bnx2x *bp,
if (mac_stopped)
msleep(20);
-
}
#define BNX2X_PREV_UNDI_PROD_ADDR(p) (BAR_TSTRORM_INTMEM + 0x1508 + ((p) << 4))
@@ -9780,6 +9858,21 @@ static bool bnx2x_prev_is_path_marked(struct bnx2x *bp)
return rc;
}
+bool bnx2x_port_after_undi(struct bnx2x *bp)
+{
+ struct bnx2x_prev_path_list *entry;
+ bool val;
+
+ down(&bnx2x_prev_sem);
+
+ entry = bnx2x_prev_path_get_entry(bp);
+ val = !!(entry && (entry->undi & (1 << BP_PORT(bp))));
+
+ up(&bnx2x_prev_sem);
+
+ return val;
+}
+
static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi)
{
struct bnx2x_prev_path_list *tmp_list;
@@ -9839,7 +9932,6 @@ static int bnx2x_do_flr(struct bnx2x *bp)
u16 status;
struct pci_dev *dev = bp->pdev;
-
if (CHIP_IS_E1x(bp)) {
BNX2X_DEV_INFO("FLR not supported in E1/E1H\n");
return -EINVAL;
@@ -9986,7 +10078,6 @@ static int bnx2x_prev_unload_common(struct bnx2x *bp)
if (!timer_count)
BNX2X_ERR("Failed to empty BRB, hope for the best\n");
-
}
/* No packets are in the pipeline, path is ready for reset */
@@ -10036,7 +10127,6 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
{
int time_counter = 10;
u32 rc, fw, hw_lock_reg, hw_lock_val;
- struct bnx2x_prev_path_list *prev_list;
BNX2X_DEV_INFO("Entering Previous Unload Flow\n");
/* clear hw from errors which may have resulted from an interrupted
@@ -10049,7 +10139,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
(MISC_REG_DRIVER_CONTROL_1 + BP_FUNC(bp) * 8) :
(MISC_REG_DRIVER_CONTROL_7 + (BP_FUNC(bp) - 6) * 8);
- hw_lock_val = (REG_RD(bp, hw_lock_reg));
+ hw_lock_val = REG_RD(bp, hw_lock_reg);
if (hw_lock_val) {
if (hw_lock_val & HW_LOCK_RESOURCE_NVRAM) {
BNX2X_DEV_INFO("Release Previously held NVRAM lock\n");
@@ -10064,7 +10154,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
if (MCPR_ACCESS_LOCK_LOCK & REG_RD(bp, MCP_REG_MCPR_ACCESS_LOCK)) {
BNX2X_DEV_INFO("Release previously held alr\n");
- REG_WR(bp, MCP_REG_MCPR_ACCESS_LOCK, 0);
+ bnx2x_release_alr(bp);
}
do {
@@ -10093,7 +10183,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
break;
}
- /* non-common reply from MCP night require looping */
+ /* non-common reply from MCP might require looping */
rc = bnx2x_prev_unload_uncommon(bp);
if (rc != BNX2X_PREV_WAIT_NEEDED)
break;
@@ -10107,8 +10197,7 @@ static int bnx2x_prev_unload(struct bnx2x *bp)
}
/* Mark function if its port was used to boot from SAN */
- prev_list = bnx2x_prev_path_get_entry(bp);
- if (prev_list && (prev_list->undi & (1 << BP_PORT(bp))))
+ if (bnx2x_port_after_undi(bp))
bp->link_params.feature_config_flags |=
FEATURE_CONFIG_BOOT_FROM_SAN;
@@ -10192,8 +10281,6 @@ static void bnx2x_get_common_hwinfo(struct bnx2x *bp)
bnx2x_init_shmem(bp);
-
-
bp->common.shmem2_base = REG_RD(bp, (BP_PATH(bp) ?
MISC_REG_GENERIC_CR_1 :
MISC_REG_GENERIC_CR_0));
@@ -10454,7 +10541,6 @@ static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg)
if (!(bp->link_params.speed_cap_mask[idx] &
PORT_HW_CFG_SPEED_CAPABILITY_D0_10G))
bp->port.supported[idx] &= ~SUPPORTED_10000baseT_Full;
-
}
BNX2X_DEV_INFO("supported 0x%x 0x%x\n", bp->port.supported[0],
@@ -10765,7 +10851,6 @@ void bnx2x_get_iscsi_info(struct bnx2x *bp)
*/
if (!bp->cnic_eth_dev.max_iscsi_conn)
bp->flags |= no_flags;
-
}
static void bnx2x_get_ext_wwn_info(struct bnx2x *bp, int func)
@@ -10782,12 +10867,56 @@ static void bnx2x_get_ext_wwn_info(struct bnx2x *bp, int func)
bp->cnic_eth_dev.fcoe_wwn_node_name_lo =
MF_CFG_RD(bp, func_ext_config[func].fcoe_wwn_node_name_lower);
}
+
+static int bnx2x_shared_fcoe_funcs(struct bnx2x *bp)
+{
+ u8 count = 0;
+
+ if (IS_MF(bp)) {
+ u8 fid;
+
+ /* iterate over absolute function ids for this path: */
+ for (fid = BP_PATH(bp); fid < E2_FUNC_MAX * 2; fid += 2) {
+ if (IS_MF_SD(bp)) {
+ u32 cfg = MF_CFG_RD(bp,
+ func_mf_config[fid].config);
+
+ if (!(cfg & FUNC_MF_CFG_FUNC_HIDE) &&
+ ((cfg & FUNC_MF_CFG_PROTOCOL_MASK) ==
+ FUNC_MF_CFG_PROTOCOL_FCOE))
+ count++;
+ } else {
+ u32 cfg = MF_CFG_RD(bp,
+ func_ext_config[fid].
+ func_cfg);
+
+ if ((cfg & MACP_FUNC_CFG_FLAGS_ENABLED) &&
+ (cfg & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD))
+ count++;
+ }
+ }
+ } else { /* SF */
+ int port, port_cnt = CHIP_MODE_IS_4_PORT(bp) ? 2 : 1;
+
+ for (port = 0; port < port_cnt; port++) {
+ u32 lic = SHMEM_RD(bp,
+ drv_lic_key[port].max_fcoe_conn) ^
+ FW_ENCODE_32BIT_PATTERN;
+ if (lic)
+ count++;
+ }
+ }
+
+ return count;
+}
+
static void bnx2x_get_fcoe_info(struct bnx2x *bp)
{
int port = BP_PORT(bp);
int func = BP_ABS_FUNC(bp);
u32 max_fcoe_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp,
drv_lic_key[port].max_fcoe_conn);
+ u8 num_fcoe_func = bnx2x_shared_fcoe_funcs(bp);
if (!CNIC_SUPPORT(bp)) {
bp->flags |= NO_FCOE_FLAG;
@@ -10801,9 +10930,10 @@ static void bnx2x_get_fcoe_info(struct bnx2x *bp)
/* Calculate the number of maximum allowed FCoE tasks */
bp->cnic_eth_dev.max_fcoe_exchanges = MAX_NUM_FCOE_TASKS_PER_ENGINE;
- if (IS_MF(bp) || CHIP_MODE_IS_4_PORT(bp))
- bp->cnic_eth_dev.max_fcoe_exchanges /=
- MAX_FCOE_FUNCS_PER_ENGINE;
+
+ /* check if FCoE resources must be shared between different functions */
+ if (num_fcoe_func)
+ bp->cnic_eth_dev.max_fcoe_exchanges /= num_fcoe_func;
/* Read the WWN: */
if (!IS_MF(bp)) {
@@ -11031,7 +11161,7 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp)
} else {
bp->common.int_block = INT_BLOCK_IGU;
- /* do not allow device reset during IGU info preocessing */
+ /* do not allow device reset during IGU info processing */
bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RESET);
val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION);
@@ -11110,7 +11240,7 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp)
E1H_FUNC_MAX * sizeof(struct drv_func_mb);
/*
* get mf configuration:
- * 1. existence of MF configuration
+ * 1. Existence of MF configuration
* 2. MAC address must be legal (check only upper bytes)
* for Switch-Independent mode;
* OVLAN must be legal for Switch-Dependent mode
@@ -11384,7 +11514,6 @@ static int bnx2x_init_bp(struct bnx2x *bp)
mutex_init(&bp->fw_mb_mutex);
spin_lock_init(&bp->stats_lock);
-
INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task);
@@ -11393,7 +11522,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
if (rc)
return rc;
} else {
- random_ether_addr(bp->dev->dev_addr);
+ eth_zero_addr(bp->dev->dev_addr);
}
bnx2x_set_modes_bitmap(bp);
@@ -11417,7 +11546,6 @@ static int bnx2x_init_bp(struct bnx2x *bp)
bnx2x_prev_unload(bp);
}
-
if (CHIP_REV_IS_FPGA(bp))
dev_err(&bp->pdev->dev, "FPGA detected\n");
@@ -11489,7 +11617,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
/* We need at least one default status block for slow-path events,
* second status block for the L2 queue, and a third status block for
- * CNIC if supproted.
+ * CNIC if supported.
*/
if (CNIC_SUPPORT(bp))
bp->min_msix_vec_cnt = 3;
@@ -11500,7 +11628,6 @@ static int bnx2x_init_bp(struct bnx2x *bp)
return rc;
}
-
/****************************************************************************
* General service functions
****************************************************************************/
@@ -11585,9 +11712,6 @@ static int bnx2x_close(struct net_device *dev)
/* Unload the driver, release IRQs */
bnx2x_nic_unload(bp, UNLOAD_CLOSE, false);
- /* Power off */
- bnx2x_set_power_state(bp, PCI_D3hot);
-
return 0;
}
@@ -11852,6 +11976,10 @@ static int bnx2x_validate_addr(struct net_device *dev)
{
struct bnx2x *bp = netdev_priv(dev);
+ /* query the bulletin board for mac address configured by the PF */
+ if (IS_VF(bp))
+ bnx2x_sample_bulletin(bp);
+
if (!bnx2x_is_valid_ether_addr(bp, dev->dev_addr)) {
BNX2X_ERR("Non-valid Ethernet address\n");
return -EADDRNOTAVAIL;
@@ -11878,12 +12006,16 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_setup_tc = bnx2x_setup_tc,
#ifdef CONFIG_BNX2X_SRIOV
.ndo_set_vf_mac = bnx2x_set_vf_mac,
- .ndo_set_vf_vlan = bnx2x_set_vf_vlan,
+ .ndo_set_vf_vlan = bnx2x_set_vf_vlan,
.ndo_get_vf_config = bnx2x_get_vf_config,
#endif
#ifdef NETDEV_FCOE_WWNN
.ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn,
#endif
+
+#ifdef CONFIG_NET_LL_RX_POLL
+ .ndo_ll_poll = bnx2x_low_latency_recv,
+#endif
};
static int bnx2x_set_coherency_mask(struct bnx2x *bp)
@@ -11959,7 +12091,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
}
if (IS_PF(bp)) {
- bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ bp->pm_cap = pdev->pm_cap;
if (bp->pm_cap == 0) {
dev_err(&bp->pdev->dev,
"Cannot find power management capability, aborting\n");
@@ -12008,8 +12140,6 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
}
BNX2X_DEV_INFO("me reg PF num: %d\n", bp->pf_num);
- bnx2x_set_power_state(bp, PCI_D0);
-
/* clean indirect addresses */
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
PCICFG_VENDOR_ID_OFFSET);
@@ -12094,15 +12224,26 @@ err_out:
return rc;
}
-static void bnx2x_get_pcie_width_speed(struct bnx2x *bp, int *width, int *speed)
+static void bnx2x_get_pcie_width_speed(struct bnx2x *bp, int *width,
+ enum bnx2x_pci_bus_speed *speed)
{
- u32 val = 0;
+ u32 link_speed, val = 0;
pci_read_config_dword(bp->pdev, PCICFG_LINK_CONTROL, &val);
*width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
- /* return value of 1=2.5GHz 2=5GHz */
- *speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
+ link_speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT;
+
+ switch (link_speed) {
+ case 3:
+ *speed = BNX2X_PCI_LINK_SPEED_8000;
+ break;
+ case 2:
+ *speed = BNX2X_PCI_LINK_SPEED_5000;
+ break;
+ default:
+ *speed = BNX2X_PCI_LINK_SPEED_2500;
+ }
}
static int bnx2x_check_firmware(struct bnx2x *bp)
@@ -12327,7 +12468,6 @@ static void bnx2x_release_firmware(struct bnx2x *bp)
bp->firmware = NULL;
}
-
static struct bnx2x_func_sp_drv_ops bnx2x_func_sp_drv = {
.init_hw_cmn_chip = bnx2x_init_hw_common_chip,
.init_hw_cmn = bnx2x_init_hw_common,
@@ -12465,7 +12605,8 @@ static int bnx2x_init_one(struct pci_dev *pdev,
{
struct net_device *dev = NULL;
struct bnx2x *bp;
- int pcie_width, pcie_speed;
+ int pcie_width;
+ enum bnx2x_pci_bus_speed pcie_speed;
int rc, max_non_def_sbs;
int rx_count, tx_count, rss_count, doorbell_size;
int max_cos_est;
@@ -12605,7 +12746,6 @@ static int bnx2x_init_one(struct pci_dev *pdev,
}
BNX2X_DEV_INFO("device name after netdev register %s\n", dev->name);
-
if (!NO_FCOE(bp)) {
/* Add storage MAC address */
rtnl_lock();
@@ -12617,15 +12757,15 @@ static int bnx2x_init_one(struct pci_dev *pdev,
BNX2X_DEV_INFO("got pcie width %d and speed %d\n",
pcie_width, pcie_speed);
- BNX2X_DEV_INFO(
- "%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
- board_info[ent->driver_data].name,
- (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
- pcie_width,
- ((!CHIP_IS_E2(bp) && pcie_speed == 2) ||
- (CHIP_IS_E2(bp) && pcie_speed == 1)) ?
- "5GHz (Gen2)" : "2.5GHz",
- dev->base_addr, bp->pdev->irq, dev->dev_addr);
+ BNX2X_DEV_INFO("%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
+ board_info[ent->driver_data].name,
+ (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4),
+ pcie_width,
+ pcie_speed == BNX2X_PCI_LINK_SPEED_2500 ? "2.5GHz" :
+ pcie_speed == BNX2X_PCI_LINK_SPEED_5000 ? "5.0GHz" :
+ pcie_speed == BNX2X_PCI_LINK_SPEED_8000 ? "8.0GHz" :
+ "Unknown",
+ dev->base_addr, bp->pdev->irq, dev->dev_addr);
return 0;
@@ -12647,17 +12787,11 @@ init_one_exit:
return rc;
}
-static void bnx2x_remove_one(struct pci_dev *pdev)
+static void __bnx2x_remove(struct pci_dev *pdev,
+ struct net_device *dev,
+ struct bnx2x *bp,
+ bool remove_netdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct bnx2x *bp;
-
- if (!dev) {
- dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
- return;
- }
- bp = netdev_priv(dev);
-
/* Delete storage MAC address */
if (!NO_FCOE(bp)) {
rtnl_lock();
@@ -12670,7 +12804,15 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
bnx2x_dcbnl_update_applist(bp, true);
#endif
- unregister_netdev(dev);
+ /* Close the interface - either directly or implicitly */
+ if (remove_netdev) {
+ unregister_netdev(dev);
+ } else {
+ rtnl_lock();
+ if (netif_running(dev))
+ bnx2x_close(dev);
+ rtnl_unlock();
+ }
/* Power on: we can't let PCI layer write to us while we are in D3 */
if (IS_PF(bp))
@@ -12692,6 +12834,12 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
if (IS_VF(bp))
bnx2x_vfpf_release(bp);
+ /* Assumes no further PCIe PM changes will occur */
+ if (system_state == SYSTEM_POWER_OFF) {
+ pci_wake_from_d3(pdev, bp->wol);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
+
if (bp->regview)
iounmap(bp->regview);
@@ -12706,7 +12854,8 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
}
bnx2x_free_mem_bp(bp);
- free_netdev(dev);
+ if (remove_netdev)
+ free_netdev(dev);
if (atomic_read(&pdev->enable_cnt) == 1)
pci_release_regions(pdev);
@@ -12715,6 +12864,20 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
+static void bnx2x_remove_one(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct bnx2x *bp;
+
+ if (!dev) {
+ dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n");
+ return;
+ }
+ bp = netdev_priv(dev);
+
+ __bnx2x_remove(pdev, dev, bp, true);
+}
+
static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
{
bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
@@ -12747,19 +12910,6 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
return 0;
}
-static void bnx2x_eeh_recover(struct bnx2x *bp)
-{
- u32 val;
-
- mutex_init(&bp->port.phy_mutex);
-
-
- val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
- if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
- != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
- BNX2X_ERR("BAD MCP validity signature\n");
-}
-
/**
* bnx2x_io_error_detected - called when PCI error is detected
* @pdev: Pointer to PCI device
@@ -12828,6 +12978,10 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
if (netif_running(dev)) {
BNX2X_ERR("IO slot reset --> driver unload\n");
+
+ /* MCP should have been reset; Need to wait for validity */
+ bnx2x_init_shmem(bp);
+
if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
u32 v;
@@ -12849,7 +13003,7 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev)
bnx2x_prev_unload(bp);
- /* We should have resetted the engine, so It's fair to
+ /* We should have reseted the engine, so It's fair to
* assume the FW will no longer write to the bnx2x driver.
*/
bnx2x_squeeze_objects(bp);
@@ -12886,8 +13040,6 @@ static void bnx2x_io_resume(struct pci_dev *pdev)
rtnl_lock();
- bnx2x_eeh_recover(bp);
-
bp->fw_seq = SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
DRV_MSG_SEQ_NUMBER_MASK;
@@ -12905,6 +13057,29 @@ static const struct pci_error_handlers bnx2x_err_handler = {
.resume = bnx2x_io_resume,
};
+static void bnx2x_shutdown(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct bnx2x *bp;
+
+ if (!dev)
+ return;
+
+ bp = netdev_priv(dev);
+ if (!bp)
+ return;
+
+ rtnl_lock();
+ netif_device_detach(dev);
+ rtnl_unlock();
+
+ /* Don't remove the netdevice, as there are scenarios which will cause
+ * the kernel to hang, e.g., when trying to remove bnx2i while the
+ * rootfs is mounted from SAN.
+ */
+ __bnx2x_remove(pdev, dev, bp, false);
+}
+
static struct pci_driver bnx2x_pci_driver = {
.name = DRV_MODULE_NAME,
.id_table = bnx2x_pci_tbl,
@@ -12916,6 +13091,7 @@ static struct pci_driver bnx2x_pci_driver = {
#ifdef CONFIG_BNX2X_SRIOV
.sriov_configure = bnx2x_sriov_configure,
#endif
+ .shutdown = bnx2x_shutdown,
};
static int __init bnx2x_init(void)
@@ -12941,11 +13117,12 @@ static int __init bnx2x_init(void)
static void __exit bnx2x_cleanup(void)
{
struct list_head *pos, *q;
+
pci_unregister_driver(&bnx2x_pci_driver);
destroy_workqueue(bnx2x_wq);
- /* Free globablly allocated resources */
+ /* Free globally allocated resources */
list_for_each_safe(pos, q, &bnx2x_prev_list) {
struct bnx2x_prev_path_list *tmp =
list_entry(pos, struct bnx2x_prev_path_list, list);
@@ -12968,7 +13145,7 @@ module_exit(bnx2x_cleanup);
* @bp: driver handle
* @set: set or clear the CAM entry
*
- * This function will wait until the ramdord completion returns.
+ * This function will wait until the ramrod completion returns.
* Return 0 if success, -ENODEV if ramrod doesn't return.
*/
static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp)
@@ -12996,7 +13173,6 @@ static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
BUG_ON(bp->cnic_spq_pending < count);
bp->cnic_spq_pending -= count;
-
for (; bp->cnic_kwq_pending; bp->cnic_kwq_pending--) {
u16 type = (le16_to_cpu(bp->cnic_kwq_cons->hdr.type)
& SPE_HDR_CONN_TYPE) >>
@@ -13169,7 +13345,6 @@ static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err)
bnx2x_cnic_sp_post(bp, 0);
}
-
/* Called with netif_addr_lock_bh() taken.
* Sets an rx_mode config for an iSCSI ETH client.
* Doesn't block.
@@ -13210,7 +13385,6 @@ static void bnx2x_set_iscsi_eth_rx_mode(struct bnx2x *bp, bool start)
}
}
-
static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
{
struct bnx2x *bp = netdev_priv(dev);
@@ -13398,7 +13572,6 @@ void bnx2x_setup_cnic_info(struct bnx2x *bp)
{
struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
-
cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) +
bnx2x_cid_ilt_lines(bp);
cp->starting_cid = bnx2x_cid_ilt_lines(bp) * ILT_PAGE_CIDS;
@@ -13434,7 +13607,6 @@ static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
BNX2X_ERR("CNIC-related load failed\n");
return rc;
}
-
}
bp->cnic_enabled = true;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
index d22bc40..8e627b8 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h
@@ -35,6 +35,8 @@
#define ATC_REG_ATC_INT_STS_CLR 0x1101c0
/* [RW 5] Parity mask register #0 read/write */
#define ATC_REG_ATC_PRTY_MASK 0x1101d8
+/* [R 5] Parity register #0 read */
+#define ATC_REG_ATC_PRTY_STS 0x1101cc
/* [RC 5] Parity register #0 read clear */
#define ATC_REG_ATC_PRTY_STS_CLR 0x1101d0
/* [RW 19] Interrupt mask register #0 read/write */
@@ -2750,6 +2752,8 @@
#define PBF_REG_PBF_INT_STS 0x1401c8
/* [RW 20] Parity mask register #0 read/write */
#define PBF_REG_PBF_PRTY_MASK 0x1401e4
+/* [R 28] Parity register #0 read */
+#define PBF_REG_PBF_PRTY_STS 0x1401d8
/* [RC 20] Parity register #0 read clear */
#define PBF_REG_PBF_PRTY_STS_CLR 0x1401dc
/* [RW 16] The Ethernet type value for L2 tag 0 */
@@ -4517,6 +4521,8 @@
#define TM_REG_TM_INT_STS 0x1640f0
/* [RW 7] Parity mask register #0 read/write */
#define TM_REG_TM_PRTY_MASK 0x16410c
+/* [R 7] Parity register #0 read */
+#define TM_REG_TM_PRTY_STS 0x164100
/* [RC 7] Parity register #0 read clear */
#define TM_REG_TM_PRTY_STS_CLR 0x164104
/* [RW 8] The event id for aggregated interrupt 0 */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
index 32a9609..8f03c98 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
@@ -35,9 +35,9 @@
/**
* bnx2x_exe_queue_init - init the Exe Queue object
*
- * @o: poiter to the object
+ * @o: pointer to the object
* @exe_len: length
- * @owner: poiter to the owner
+ * @owner: pointer to the owner
* @validate: validate function pointer
* @optimize: optimize function pointer
* @exec: execute function pointer
@@ -142,7 +142,6 @@ free_and_exit:
spin_unlock_bh(&o->lock);
return rc;
-
}
static inline void __bnx2x_exe_queue_reset_pending(
@@ -163,13 +162,11 @@ static inline void __bnx2x_exe_queue_reset_pending(
static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp,
struct bnx2x_exe_queue_obj *o)
{
-
spin_lock_bh(&o->lock);
__bnx2x_exe_queue_reset_pending(bp, o);
spin_unlock_bh(&o->lock);
-
}
/**
@@ -179,7 +176,7 @@ static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp,
* @o: queue
* @ramrod_flags: flags
*
- * (Atomicy is ensured using the exe_queue->lock).
+ * (Atomicity is ensured using the exe_queue->lock).
*/
static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
struct bnx2x_exe_queue_obj *o,
@@ -192,8 +189,7 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
spin_lock_bh(&o->lock);
- /*
- * Next step should not be performed until the current is finished,
+ /* Next step should not be performed until the current is finished,
* unless a DRV_CLEAR_ONLY bit is set. In this case we just want to
* properly clear object internals without sending any command to the FW
* which also implies there won't be any completion to clear the
@@ -209,8 +205,7 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
}
}
- /*
- * Run through the pending commands list and create a next
+ /* Run through the pending commands list and create a next
* execution chunk.
*/
while (!list_empty(&o->exe_queue)) {
@@ -220,8 +215,7 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
if (cur_len + elem->cmd_len <= o->exe_chunk_len) {
cur_len += elem->cmd_len;
- /*
- * Prevent from both lists being empty when moving an
+ /* Prevent from both lists being empty when moving an
* element. This will allow the call of
* bnx2x_exe_queue_empty() without locking.
*/
@@ -241,14 +235,12 @@ static inline int bnx2x_exe_queue_step(struct bnx2x *bp,
rc = o->execute(bp, o->owner, &o->pending_comp, ramrod_flags);
if (rc < 0)
- /*
- * In case of an error return the commands back to the queue
- * and reset the pending_comp.
+ /* In case of an error return the commands back to the queue
+ * and reset the pending_comp.
*/
list_splice_init(&o->pending_comp, &o->exe_queue);
else if (!rc)
- /*
- * If zero is returned, means there are no outstanding pending
+ /* If zero is returned, means there are no outstanding pending
* completions and we may dismiss the pending list.
*/
__bnx2x_exe_queue_reset_pending(bp, o);
@@ -308,7 +300,6 @@ static inline int bnx2x_state_wait(struct bnx2x *bp, int state,
/* can take a while if any port is running */
int cnt = 5000;
-
if (CHIP_REV_IS_EMUL(bp))
cnt *= 20;
@@ -456,7 +447,6 @@ static int bnx2x_get_n_elements(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o,
DP(BNX2X_MSG_SP, "copied element number %d to address %p element was:\n",
counter, next);
next += stride + size;
-
}
}
return counter * ETH_ALEN;
@@ -518,7 +508,6 @@ static int bnx2x_check_vlan_mac_add(struct bnx2x *bp,
return 0;
}
-
/* check_del() callbacks */
static struct bnx2x_vlan_mac_registry_elem *
bnx2x_check_mac_del(struct bnx2x *bp,
@@ -609,7 +598,6 @@ static bool bnx2x_check_move_always_err(
return false;
}
-
static inline u8 bnx2x_vlan_mac_get_rx_tx_flag(struct bnx2x_vlan_mac_obj *o)
{
struct bnx2x_raw_obj *raw = &o->raw;
@@ -626,7 +614,6 @@ static inline u8 bnx2x_vlan_mac_get_rx_tx_flag(struct bnx2x_vlan_mac_obj *o)
return rx_tx_flag;
}
-
void bnx2x_set_mac_in_nig(struct bnx2x *bp,
bool add, unsigned char *dev_addr, int index)
{
@@ -693,7 +680,7 @@ static inline void bnx2x_vlan_mac_set_cmd_hdr_e2(struct bnx2x *bp,
*
* @cid: connection id
* @type: BNX2X_FILTER_XXX_PENDING
- * @hdr: poiter to header to setup
+ * @hdr: pointer to header to setup
* @rule_cnt:
*
* currently we always configure one rule and echo field to contain a CID and an
@@ -707,7 +694,6 @@ static inline void bnx2x_vlan_mac_set_rdata_hdr_e2(u32 cid, int type,
hdr->rule_cnt = (u8)rule_cnt;
}
-
/* hw_config() callbacks */
static void bnx2x_set_one_mac_e2(struct bnx2x *bp,
struct bnx2x_vlan_mac_obj *o,
@@ -723,8 +709,7 @@ static void bnx2x_set_one_mac_e2(struct bnx2x *bp,
unsigned long *vlan_mac_flags = &elem->cmd_data.vlan_mac.vlan_mac_flags;
u8 *mac = elem->cmd_data.vlan_mac.u.mac.mac;
- /*
- * Set LLH CAM entry: currently only iSCSI and ETH macs are
+ /* Set LLH CAM entry: currently only iSCSI and ETH macs are
* relevant. In addition, current implementation is tuned for a
* single ETH MAC.
*
@@ -879,8 +864,7 @@ static void bnx2x_set_one_mac_e1x(struct bnx2x *bp,
struct bnx2x_raw_obj *raw = &o->raw;
struct mac_configuration_cmd *config =
(struct mac_configuration_cmd *)(raw->rdata);
- /*
- * 57710 and 57711 do not support MOVE command,
+ /* 57710 and 57711 do not support MOVE command,
* so it's either ADD or DEL
*/
bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ?
@@ -960,7 +944,6 @@ static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan;
u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac;
-
/* Reset the ramrod data buffer for the first rule */
if (rule_idx == 0)
memset(data, 0, sizeof(*data));
@@ -969,7 +952,7 @@ static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp,
bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_PAIR,
&rule_entry->pair.header);
- /* Set VLAN and MAC themselvs */
+ /* Set VLAN and MAC themselves */
rule_entry->pair.vlan = cpu_to_le16(vlan);
bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb,
&rule_entry->pair.mac_mid,
@@ -1021,8 +1004,7 @@ static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp,
struct bnx2x_raw_obj *raw = &o->raw;
struct mac_configuration_cmd *config =
(struct mac_configuration_cmd *)(raw->rdata);
- /*
- * 57710 and 57711 do not support MOVE command,
+ /* 57710 and 57711 do not support MOVE command,
* so it's either ADD or DEL
*/
bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ?
@@ -1046,7 +1028,7 @@ static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp,
*
* @bp: device handle
* @p: command parameters
- * @ppos: pointer to the cooky
+ * @ppos: pointer to the cookie
*
* reconfigure next MAC/VLAN/VLAN-MAC element from the
* previously configured elements list.
@@ -1054,7 +1036,7 @@ static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp,
* from command parameters only RAMROD_COMP_WAIT bit in ramrod_flags is taken
* into an account
*
- * pointer to the cooky - that should be given back in the next call to make
+ * pointer to the cookie - that should be given back in the next call to make
* function handle the next element. If *ppos is set to NULL it will restart the
* iterator. If returned *ppos == NULL this means that the last element has been
* handled.
@@ -1102,8 +1084,7 @@ static int bnx2x_vlan_mac_restore(struct bnx2x *bp,
return bnx2x_config_vlan_mac(bp, p);
}
-/*
- * bnx2x_exeq_get_mac/bnx2x_exeq_get_vlan/bnx2x_exeq_get_vlan_mac return a
+/* bnx2x_exeq_get_mac/bnx2x_exeq_get_vlan/bnx2x_exeq_get_vlan_mac return a
* pointer to an element with a specific criteria and NULL if such an element
* hasn't been found.
*/
@@ -1187,8 +1168,7 @@ static inline int bnx2x_validate_vlan_mac_add(struct bnx2x *bp,
return rc;
}
- /*
- * Check if there is a pending ADD command for this
+ /* Check if there is a pending ADD command for this
* MAC/VLAN/VLAN-MAC. Return an error if there is.
*/
if (exeq->get(exeq, elem)) {
@@ -1196,8 +1176,7 @@ static inline int bnx2x_validate_vlan_mac_add(struct bnx2x *bp,
return -EEXIST;
}
- /*
- * TODO: Check the pending MOVE from other objects where this
+ /* TODO: Check the pending MOVE from other objects where this
* object is a destination object.
*/
@@ -1240,8 +1219,7 @@ static inline int bnx2x_validate_vlan_mac_del(struct bnx2x *bp,
return -EEXIST;
}
- /*
- * Check if there are pending DEL or MOVE commands for this
+ /* Check if there are pending DEL or MOVE commands for this
* MAC/VLAN/VLAN-MAC. Return an error if so.
*/
memcpy(&query_elem, elem, sizeof(query_elem));
@@ -1292,8 +1270,7 @@ static inline int bnx2x_validate_vlan_mac_move(struct bnx2x *bp,
struct bnx2x_exe_queue_obj *src_exeq = &src_o->exe_queue;
struct bnx2x_exe_queue_obj *dest_exeq = &dest_o->exe_queue;
- /*
- * Check if we can perform this operation based on the current registry
+ /* Check if we can perform this operation based on the current registry
* state.
*/
if (!src_o->check_move(bp, src_o, dest_o,
@@ -1302,8 +1279,7 @@ static inline int bnx2x_validate_vlan_mac_move(struct bnx2x *bp,
return -EINVAL;
}
- /*
- * Check if there is an already pending DEL or MOVE command for the
+ /* Check if there is an already pending DEL or MOVE command for the
* source object or ADD command for a destination object. Return an
* error if so.
*/
@@ -1392,7 +1368,7 @@ static int bnx2x_remove_vlan_mac(struct bnx2x *bp,
}
/**
- * bnx2x_wait_vlan_mac - passivly wait for 5 seconds until all work completes.
+ * bnx2x_wait_vlan_mac - passively wait for 5 seconds until all work completes.
*
* @bp: device handle
* @o: bnx2x_vlan_mac_obj
@@ -1550,9 +1526,8 @@ static inline int bnx2x_vlan_mac_get_registry_elem(
/* Get a new CAM offset */
if (!o->get_cam_offset(o, &reg_elem->cam_offset)) {
- /*
- * This shell never happen, because we have checked the
- * CAM availiability in the 'validate'.
+ /* This shall never happen, because we have checked the
+ * CAM availability in the 'validate'.
*/
WARN_ON(1);
kfree(reg_elem);
@@ -1599,8 +1574,7 @@ static int bnx2x_execute_vlan_mac(struct bnx2x *bp,
struct bnx2x_vlan_mac_registry_elem *reg_elem;
enum bnx2x_vlan_mac_cmd cmd;
- /*
- * If DRIVER_ONLY execution is requested, cleanup a registry
+ /* If DRIVER_ONLY execution is requested, cleanup a registry
* and exit. Otherwise send a ramrod to FW.
*/
if (!drv_only) {
@@ -1609,11 +1583,10 @@ static int bnx2x_execute_vlan_mac(struct bnx2x *bp,
/* Set pending */
r->set_pending(r);
- /* Fill tha ramrod data */
+ /* Fill the ramrod data */
list_for_each_entry(elem, exe_chunk, link) {
cmd = elem->cmd_data.vlan_mac.cmd;
- /*
- * We will add to the target object in MOVE command, so
+ /* We will add to the target object in MOVE command, so
* change the object for a CAM search.
*/
if (cmd == BNX2X_VLAN_MAC_MOVE)
@@ -1646,12 +1619,11 @@ static int bnx2x_execute_vlan_mac(struct bnx2x *bp,
idx++;
}
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
rc = bnx2x_sp_post(bp, o->ramrod_cmd, r->cid,
@@ -1766,8 +1738,7 @@ int bnx2x_config_vlan_mac(
return rc;
}
- /*
- * If nothing will be executed further in this iteration we want to
+ /* If nothing will be executed further in this iteration we want to
* return PENDING if there are pending commands
*/
if (!bnx2x_exe_queue_empty(&o->exe_queue))
@@ -1786,13 +1757,11 @@ int bnx2x_config_vlan_mac(
return rc;
}
- /*
- * RAMROD_COMP_WAIT is a superset of RAMROD_EXEC. If it was set
+ /* RAMROD_COMP_WAIT is a superset of RAMROD_EXEC. If it was set
* then user want to wait until the last command is done.
*/
if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) {
- /*
- * Wait maximum for the current exe_queue length iterations plus
+ /* Wait maximum for the current exe_queue length iterations plus
* one (for the current pending command).
*/
int max_iterations = bnx2x_exe_queue_length(&o->exe_queue) + 1;
@@ -1818,8 +1787,6 @@ int bnx2x_config_vlan_mac(
return rc;
}
-
-
/**
* bnx2x_vlan_mac_del_all - delete elements with given vlan_mac_flags spec
*
@@ -1829,7 +1796,7 @@ int bnx2x_config_vlan_mac(
* @ramrod_flags: execution flags to be used for this deletion
*
* if the last operation has completed successfully and there are no
- * moreelements left, positive value if the last operation has completed
+ * more elements left, positive value if the last operation has completed
* successfully and there are more previously configured elements, negative
* value is current operation has failed.
*/
@@ -1870,8 +1837,7 @@ static int bnx2x_vlan_mac_del_all(struct bnx2x *bp,
p.ramrod_flags = *ramrod_flags;
p.user_req.cmd = BNX2X_VLAN_MAC_DEL;
- /*
- * Add all but the last VLAN-MAC to the execution queue without actually
+ /* Add all but the last VLAN-MAC to the execution queue without actually
* execution anything.
*/
__clear_bit(RAMROD_COMP_WAIT, &p.ramrod_flags);
@@ -1934,7 +1900,6 @@ static inline void bnx2x_init_vlan_mac_common(struct bnx2x_vlan_mac_obj *o,
state, pstate, type);
}
-
void bnx2x_init_mac_obj(struct bnx2x *bp,
struct bnx2x_vlan_mac_obj *mac_obj,
u8 cl_id, u32 cid, u8 func_id, void *rdata,
@@ -2048,8 +2013,7 @@ void bnx2x_init_vlan_mac_obj(struct bnx2x *bp,
/* CAM pool handling */
vlan_mac_obj->get_credit = bnx2x_get_credit_vlan_mac;
vlan_mac_obj->put_credit = bnx2x_put_credit_vlan_mac;
- /*
- * CAM offset is relevant for 57710 and 57711 chips only which have a
+ /* CAM offset is relevant for 57710 and 57711 chips only which have a
* single CAM for both MACs and VLAN-MAC pairs. So the offset
* will be taken from MACs' pool object only.
*/
@@ -2092,7 +2056,6 @@ void bnx2x_init_vlan_mac_obj(struct bnx2x *bp,
bnx2x_execute_vlan_mac,
bnx2x_exeq_get_vlan_mac);
}
-
}
/* RX_MODE verbs: DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */
@@ -2117,12 +2080,12 @@ static int bnx2x_set_rx_mode_e1x(struct bnx2x *bp,
struct tstorm_eth_mac_filter_config *mac_filters =
(struct tstorm_eth_mac_filter_config *)p->rdata;
- /* initial seeting is drop-all */
+ /* initial setting is drop-all */
u8 drop_all_ucast = 1, drop_all_mcast = 1;
u8 accp_all_ucast = 0, accp_all_bcast = 0, accp_all_mcast = 0;
u8 unmatched_unicast = 0;
- /* In e1x there we only take into account rx acceot flag since tx switching
+ /* In e1x there we only take into account rx accept flag since tx switching
* isn't enabled. */
if (test_bit(BNX2X_ACCEPT_UNICAST, &p->rx_accept_flags))
/* accept matched ucast */
@@ -2245,7 +2208,6 @@ static inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp,
}
cmd->state = cpu_to_le16(state);
-
}
static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
@@ -2286,9 +2248,7 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
false);
}
-
- /*
- * If FCoE Queue configuration has been requested configure the Rx and
+ /* If FCoE Queue configuration has been requested configure the Rx and
* internal switching modes for this queue in separate rules.
*
* FCoE queue shell never be set to ACCEPT_ALL packets of any sort:
@@ -2324,8 +2284,7 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
}
}
- /*
- * Set the ramrod header (most importantly - number of rules to
+ /* Set the ramrod header (most importantly - number of rules to
* configure).
*/
bnx2x_rx_mode_set_rdata_hdr_e2(p->cid, &data->header, rule_idx);
@@ -2334,12 +2293,11 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
data->header.rule_cnt, p->rx_accept_flags,
p->tx_accept_flags);
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
/* Send a ramrod */
@@ -2476,7 +2434,7 @@ static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp,
cur_mac = (struct bnx2x_mcast_mac_elem *)
((u8 *)new_cmd + sizeof(*new_cmd));
- /* Push the MACs of the current command into the pendig command
+ /* Push the MACs of the current command into the pending command
* MACs list: FIFO
*/
list_for_each_entry(pos, &p->mcast_list, link) {
@@ -2909,7 +2867,6 @@ static int bnx2x_mcast_validate_e2(struct bnx2x *bp,
default:
BNX2X_ERR("Unknown command: %d\n", cmd);
return -EINVAL;
-
}
/* Increase the total number of MACs pending to be configured */
@@ -3034,20 +2991,18 @@ static int bnx2x_mcast_setup_e2(struct bnx2x *bp,
if (!o->total_pending_num)
bnx2x_mcast_refresh_registry_e2(bp, o);
- /*
- * If CLEAR_ONLY was requested - don't send a ramrod and clear
+ /* If CLEAR_ONLY was requested - don't send a ramrod and clear
* RAMROD_PENDING status immediately.
*/
if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) {
raw->clear_pending(raw);
return 0;
} else {
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
/* Send a ramrod */
@@ -3121,7 +3076,7 @@ static inline void bnx2x_mcast_hdl_restore_e1h(struct bnx2x *bp,
}
}
-/* On 57711 we write the multicast MACs' aproximate match
+/* On 57711 we write the multicast MACs' approximate match
* table by directly into the TSTORM's internal RAM. So we don't
* really need to handle any tricks to make it work.
*/
@@ -3223,7 +3178,6 @@ static int bnx2x_mcast_validate_e1(struct bnx2x *bp,
default:
BNX2X_ERR("Unknown command: %d\n", cmd);
return -EINVAL;
-
}
/* We want to ensure that commands are executed one by one for 57710.
@@ -3245,7 +3199,7 @@ static void bnx2x_mcast_revert_e1(struct bnx2x *bp,
/* If current command hasn't been handled yet and we are
* here means that it's meant to be dropped and we have to
- * update the number of outstandling MACs accordingly.
+ * update the number of outstanding MACs accordingly.
*/
if (p->mcast_list_len)
o->total_pending_num -= o->max_cmd_len;
@@ -3342,7 +3296,6 @@ static inline int bnx2x_mcast_handle_restore_cmd_e1(
return -1;
}
-
static inline int bnx2x_mcast_handle_pending_cmds_e1(
struct bnx2x *bp, struct bnx2x_mcast_ramrod_params *p)
{
@@ -3352,7 +3305,6 @@ static inline int bnx2x_mcast_handle_pending_cmds_e1(
union bnx2x_mcast_config_data cfg_data = {NULL};
int cnt = 0;
-
/* If nothing to be done - return */
if (list_empty(&o->pending_cmds_head))
return 0;
@@ -3523,20 +3475,18 @@ static int bnx2x_mcast_setup_e1(struct bnx2x *bp,
if (rc)
return rc;
- /*
- * If CLEAR_ONLY was requested - don't send a ramrod and clear
+ /* If CLEAR_ONLY was requested - don't send a ramrod and clear
* RAMROD_PENDING status immediately.
*/
if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) {
raw->clear_pending(raw);
return 0;
} else {
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
/* Send a ramrod */
@@ -3550,7 +3500,6 @@ static int bnx2x_mcast_setup_e1(struct bnx2x *bp,
/* Ramrod completion is pending */
return 1;
}
-
}
static int bnx2x_mcast_get_registry_size_exact(struct bnx2x_mcast_obj *o)
@@ -3848,7 +3797,6 @@ static bool bnx2x_credit_pool_always_true(struct bnx2x_credit_pool_obj *o,
return true;
}
-
static bool bnx2x_credit_pool_get_entry(
struct bnx2x_credit_pool_obj *o,
int *offset)
@@ -3999,8 +3947,7 @@ void bnx2x_init_mac_credit_pool(struct bnx2x *bp,
} else {
- /*
- * CAM credit is equaly divided between all active functions
+ /* CAM credit is equaly divided between all active functions
* on the PATH.
*/
if ((func_num > 0)) {
@@ -4009,8 +3956,7 @@ void bnx2x_init_mac_credit_pool(struct bnx2x *bp,
else
cam_sz = BNX2X_CAM_SIZE_EMUL;
- /*
- * No need for CAM entries handling for 57712 and
+ /* No need for CAM entries handling for 57712 and
* newer.
*/
bnx2x_init_credit_pool(p, -1, cam_sz);
@@ -4018,7 +3964,6 @@ void bnx2x_init_mac_credit_pool(struct bnx2x *bp,
/* this should never happen! Block MAC operations. */
bnx2x_init_credit_pool(p, 0, 0);
}
-
}
}
@@ -4028,14 +3973,12 @@ void bnx2x_init_vlan_credit_pool(struct bnx2x *bp,
u8 func_num)
{
if (CHIP_IS_E1x(bp)) {
- /*
- * There is no VLAN credit in HW on 57710 and 57711 only
+ /* There is no VLAN credit in HW on 57710 and 57711 only
* MAC / MAC-VLAN can be set
*/
bnx2x_init_credit_pool(p, 0, -1);
} else {
- /*
- * CAM credit is equaly divided between all active functions
+ /* CAM credit is equally divided between all active functions
* on the PATH.
*/
if (func_num > 0) {
@@ -4051,7 +3994,7 @@ void bnx2x_init_vlan_credit_pool(struct bnx2x *bp,
/**
* bnx2x_debug_print_ind_table - prints the indirection table configuration.
*
- * @bp: driver hanlde
+ * @bp: driver handle
* @p: pointer to rss configuration
*
* Prints it when NETIF_MSG_IFUP debug level is configured.
@@ -4164,12 +4107,11 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
data->capabilities |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
}
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
/* Send a ramrod */
@@ -4215,7 +4157,6 @@ int bnx2x_config_rss(struct bnx2x *bp,
return rc;
}
-
void bnx2x_init_rss_config_obj(struct bnx2x *bp,
struct bnx2x_rss_config_obj *rss_obj,
u8 cl_id, u32 cid, u8 func_id, u8 engine_id,
@@ -4288,7 +4229,6 @@ int bnx2x_queue_state_change(struct bnx2x *bp,
return !!test_bit(pending_bit, pending);
}
-
static int bnx2x_queue_set_pending(struct bnx2x_queue_sp_obj *obj,
struct bnx2x_queue_state_params *params)
{
@@ -4337,7 +4277,7 @@ static int bnx2x_queue_comp_cmd(struct bnx2x *bp,
}
if (o->next_tx_only >= o->max_cos)
- /* >= becuase tx only must always be smaller than cos since the
+ /* >= because tx only must always be smaller than cos since the
* primary connection supports COS 0
*/
BNX2X_ERR("illegal value for next tx_only: %d. max cos was %d",
@@ -4403,7 +4343,6 @@ static void bnx2x_q_fill_init_general_data(struct bnx2x *bp,
gen_data->mtu = cpu_to_le16(params->mtu);
gen_data->func_id = o->func_id;
-
gen_data->cos = params->cos;
gen_data->traffic_type =
@@ -4530,7 +4469,6 @@ static void bnx2x_q_fill_init_rx_data(struct bnx2x_queue_sp_obj *o,
cpu_to_le16(params->silent_removal_value);
rx_data->silent_vlan_mask =
cpu_to_le16(params->silent_removal_mask);
-
}
/* initialize the general, tx and rx parts of a queue object */
@@ -4652,12 +4590,11 @@ static inline int bnx2x_q_send_setup_e1x(struct bnx2x *bp,
/* Fill the ramrod data */
bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
@@ -4681,12 +4618,11 @@ static inline int bnx2x_q_send_setup_e2(struct bnx2x *bp,
bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
bnx2x_q_fill_setup_data_e2(bp, params, rdata);
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
@@ -4706,7 +4642,6 @@ static inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp,
&params->params.tx_only;
u8 cid_index = tx_only_params->cid_index;
-
if (cid_index >= o->max_cos) {
BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n",
o->cl_id, cid_index);
@@ -4727,12 +4662,11 @@ static inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp,
o->cids[cid_index], rdata->general.client_id,
rdata->general.sp_client_id, rdata->general.cos);
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
return bnx2x_sp_post(bp, ramrod, o->cids[cid_index],
@@ -4761,7 +4695,7 @@ static void bnx2x_q_fill_update_data(struct bnx2x *bp,
test_bit(BNX2X_Q_UPDATE_IN_VLAN_REM_CHNG,
&params->update_flags);
- /* Outer VLAN sripping */
+ /* Outer VLAN stripping */
data->outer_vlan_removal_enable_flg =
test_bit(BNX2X_Q_UPDATE_OUT_VLAN_REM, &params->update_flags);
data->outer_vlan_removal_change_flg =
@@ -4816,19 +4750,17 @@ static inline int bnx2x_q_send_update(struct bnx2x *bp,
return -EINVAL;
}
-
/* Clear the ramrod data */
memset(rdata, 0, sizeof(*rdata));
/* Fill the ramrod data */
bnx2x_q_fill_update_data(bp, o, update_params, rdata);
- /*
- * No need for an explicit memory barrier here as long we would
- * need to ensure the ordering of writing to the SPQ element
- * and updating of the SPQ producer which involves a memory
- * read and we will have to put a full memory barrier there
- * (inside bnx2x_sp_post()).
+ /* No need for an explicit memory barrier here as long we would
+ * need to ensure the ordering of writing to the SPQ element
+ * and updating of the SPQ producer which involves a memory
+ * read and we will have to put a full memory barrier there
+ * (inside bnx2x_sp_post()).
*/
return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_UPDATE,
@@ -5038,8 +4970,7 @@ static int bnx2x_queue_chk_transition(struct bnx2x *bp,
&params->params.update;
u8 next_tx_only = o->num_tx_only;
- /*
- * Forget all pending for completion commands if a driver only state
+ /* Forget all pending for completion commands if a driver only state
* transition has been requested.
*/
if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags)) {
@@ -5047,8 +4978,7 @@ static int bnx2x_queue_chk_transition(struct bnx2x *bp,
o->next_state = BNX2X_Q_STATE_MAX;
}
- /*
- * Don't allow a next state transition if we are in the middle of
+ /* Don't allow a next state transition if we are in the middle of
* the previous one.
*/
if (o->pending) {
@@ -5257,8 +5187,7 @@ enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp,
if (o->pending)
return BNX2X_F_STATE_MAX;
- /*
- * unsure the order of reading of o->pending and o->state
+ /* unsure the order of reading of o->pending and o->state
* o->pending should be read first
*/
rmb();
@@ -5356,8 +5285,7 @@ static int bnx2x_func_chk_transition(struct bnx2x *bp,
enum bnx2x_func_state state = o->state, next_state = BNX2X_F_STATE_MAX;
enum bnx2x_func_cmd cmd = params->cmd;
- /*
- * Forget all pending for completion commands if a driver only state
+ /* Forget all pending for completion commands if a driver only state
* transition has been requested.
*/
if (test_bit(RAMROD_DRV_CLR_ONLY, &params->ramrod_flags)) {
@@ -5365,8 +5293,7 @@ static int bnx2x_func_chk_transition(struct bnx2x *bp,
o->next_state = BNX2X_F_STATE_MAX;
}
- /*
- * Don't allow a next state transition if we are in the middle of
+ /* Don't allow a next state transition if we are in the middle of
* the previous one.
*/
if (o->pending)
@@ -5539,7 +5466,7 @@ static int bnx2x_func_hw_init(struct bnx2x *bp,
goto init_err;
}
- /* Handle the beginning of COMMON_XXX pases separatelly... */
+ /* Handle the beginning of COMMON_XXX pases separately... */
switch (load_code) {
case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP:
rc = bnx2x_func_init_cmn_chip(bp, drv);
@@ -5573,7 +5500,7 @@ static int bnx2x_func_hw_init(struct bnx2x *bp,
init_err:
drv->gunzip_end(bp);
- /* In case of success, complete the comand immediatelly: no ramrods
+ /* In case of success, complete the command immediately: no ramrods
* have been sent.
*/
if (!rc)
@@ -5598,7 +5525,7 @@ static inline void bnx2x_func_reset_func(struct bnx2x *bp,
}
/**
- * bnx2x_func_reset_port - reser HW at port stage
+ * bnx2x_func_reset_port - reset HW at port stage
*
* @bp: device handle
* @drv:
@@ -5620,7 +5547,7 @@ static inline void bnx2x_func_reset_port(struct bnx2x *bp,
}
/**
- * bnx2x_func_reset_cmn - reser HW at common stage
+ * bnx2x_func_reset_cmn - reset HW at common stage
*
* @bp: device handle
* @drv:
@@ -5636,7 +5563,6 @@ static inline void bnx2x_func_reset_cmn(struct bnx2x *bp,
drv->reset_hw_cmn(bp);
}
-
static inline int bnx2x_func_hw_reset(struct bnx2x *bp,
struct bnx2x_func_state_params *params)
{
@@ -5663,7 +5589,7 @@ static inline int bnx2x_func_hw_reset(struct bnx2x *bp,
break;
}
- /* Complete the comand immediatelly: no ramrods have been sent. */
+ /* Complete the command immediately: no ramrods have been sent. */
o->complete_cmd(bp, o, BNX2X_F_CMD_HW_RESET);
return 0;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
index 43c00bc..798dfe9 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
@@ -34,8 +34,7 @@ enum {
RAMROD_RESTORE,
/* Execute the next command now */
RAMROD_EXEC,
- /*
- * Don't add a new command and continue execution of posponed
+ /* Don't add a new command and continue execution of postponed
* commands. If not set a new command will be added to the
* pending commands list.
*/
@@ -129,8 +128,7 @@ enum bnx2x_vlan_mac_cmd {
struct bnx2x_vlan_mac_data {
/* Requested command: BNX2X_VLAN_MAC_XX */
enum bnx2x_vlan_mac_cmd cmd;
- /*
- * used to contain the data related vlan_mac_flags bits from
+ /* used to contain the data related vlan_mac_flags bits from
* ramrod parameters.
*/
unsigned long vlan_mac_flags;
@@ -190,14 +188,10 @@ typedef struct bnx2x_exeq_elem *
struct bnx2x_exeq_elem *elem);
struct bnx2x_exe_queue_obj {
- /*
- * Commands pending for an execution.
- */
+ /* Commands pending for an execution. */
struct list_head exe_queue;
- /*
- * Commands pending for an completion.
- */
+ /* Commands pending for an completion. */
struct list_head pending_comp;
spinlock_t lock;
@@ -245,14 +239,13 @@ struct bnx2x_exe_queue_obj {
};
/***************** Classification verbs: Set/Del MAC/VLAN/VLAN-MAC ************/
/*
- * Element in the VLAN_MAC registry list having all currenty configured
+ * Element in the VLAN_MAC registry list having all currently configured
* rules.
*/
struct bnx2x_vlan_mac_registry_elem {
struct list_head link;
- /*
- * Used to store the cam offset used for the mac/vlan/vlan-mac.
+ /* Used to store the cam offset used for the mac/vlan/vlan-mac.
* Relevant for 57710 and 57711 only. VLANs and MACs share the
* same CAM for these chips.
*/
@@ -310,7 +303,7 @@ struct bnx2x_vlan_mac_obj {
* @param n number of elements to get
* @param buf buffer preallocated by caller into which elements
* will be copied. Note elements are 4-byte aligned
- * so buffer size must be able to accomodate the
+ * so buffer size must be able to accommodate the
* aligned elements.
*
* @return number of copied bytes
@@ -395,7 +388,7 @@ struct bnx2x_vlan_mac_obj {
* @param bp
* @param p Command parameters (RAMROD_COMP_WAIT bit in
* ramrod_flags is only taken into an account)
- * @param ppos a pointer to the cooky that should be given back in the
+ * @param ppos a pointer to the cookie that should be given back in the
* next call to make function handle the next element. If
* *ppos is set to NULL it will restart the iterator.
* If returned *ppos == NULL this means that the last
@@ -408,7 +401,7 @@ struct bnx2x_vlan_mac_obj {
struct bnx2x_vlan_mac_registry_elem **ppos);
/**
- * Should be called on a completion arival.
+ * Should be called on a completion arrival.
*
* @param bp
* @param o
@@ -447,7 +440,7 @@ void bnx2x_set_mac_in_nig(struct bnx2x *bp,
/** RX_MODE verbs:DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */
-/* RX_MODE ramrod spesial flags: set in rx_mode_flags field in
+/* RX_MODE ramrod special flags: set in rx_mode_flags field in
* a bnx2x_rx_mode_ramrod_params.
*/
enum {
@@ -475,8 +468,7 @@ struct bnx2x_rx_mode_ramrod_params {
unsigned long ramrod_flags;
unsigned long rx_mode_flags;
- /*
- * rdata is either a pointer to eth_filter_rules_ramrod_data(e2) or to
+ /* rdata is either a pointer to eth_filter_rules_ramrod_data(e2) or to
* a tstorm_eth_mac_filter_config (e1x).
*/
void *rdata;
@@ -646,12 +638,11 @@ struct bnx2x_credit_pool_obj {
/* Maximum allowed credit. put() will check against it. */
int pool_sz;
- /*
- * Allocate a pool table statically.
+ /* Allocate a pool table statically.
*
- * Currently the mamimum allowed size is MAX_MAC_CREDIT_E2(272)
+ * Currently the maximum allowed size is MAX_MAC_CREDIT_E2(272)
*
- * The set bit in the table will mean that the entry is available.
+ * The set bit in the table will mean that the entry is available.
*/
#define BNX2X_POOL_VEC_SIZE (MAX_MAC_CREDIT_E2 / 64)
u64 pool_mirror[BNX2X_POOL_VEC_SIZE];
@@ -832,7 +823,7 @@ enum {
BNX2X_Q_FLG_TUN_INC_INNER_IP_ID
};
-/* Queue type options: queue type may be a compination of below. */
+/* Queue type options: queue type may be a combination of below. */
enum bnx2x_q_type {
/** TODO: Consider moving both these flags into the init()
* ramrod params.
@@ -1002,10 +993,9 @@ struct bnx2x_queue_sp_obj {
u8 cl_id;
u8 func_id;
- /*
- * number of traffic classes supported by queue.
- * The primary connection of the queue suppotrs the first traffic
- * class. Any further traffic class is suppoted by a tx-only
+ /* number of traffic classes supported by queue.
+ * The primary connection of the queue supports the first traffic
+ * class. Any further traffic class is supported by a tx-only
* connection.
*
* Therefore max_cos is also a number of valid entries in the cids
@@ -1021,7 +1011,7 @@ struct bnx2x_queue_sp_obj {
/* BNX2X_Q_CMD_XX bits. This object implements "one
* pending" paradigm but for debug and tracing purposes it's
- * more convinient to have different bits for different
+ * more convenient to have different bits for different
* commands.
*/
unsigned long pending;
@@ -1210,7 +1200,7 @@ struct bnx2x_func_sp_obj {
/* BNX2X_FUNC_CMD_XX bits. This object implements "one
* pending" paradigm but for debug and tracing purposes it's
- * more convinient to have different bits for different
+ * more convenient to have different bits for different
* commands.
*/
unsigned long pending;
@@ -1329,7 +1319,7 @@ void bnx2x_init_rx_mode_obj(struct bnx2x *bp,
*
* @p: Command parameters
*
- * Return: 0 - if operation was successfull and there is no pending completions,
+ * Return: 0 - if operation was successful and there is no pending completions,
* positive number - if there are pending completions,
* negative - if there were errors
*/
@@ -1361,7 +1351,7 @@ void bnx2x_init_mcast_obj(struct bnx2x *bp,
* the current command will be enqueued to the tail of the
* pending commands list.
*
- * Return: 0 is operation was successfull and there are no pending completions,
+ * Return: 0 is operation was successful and there are no pending completions,
* negative if there were errors, positive if there are pending
* completions.
*/
@@ -1377,7 +1367,6 @@ void bnx2x_init_vlan_credit_pool(struct bnx2x *bp,
struct bnx2x_credit_pool_obj *p, u8 func_id,
u8 func_num);
-
/****************** RSS CONFIGURATION ****************/
void bnx2x_init_rss_config_obj(struct bnx2x *bp,
struct bnx2x_rss_config_obj *rss_obj,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 2ce7c74..8a556dd 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -1341,7 +1341,7 @@ int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
*/
/* internal vf enable - until vf is enabled internally all transactions
- * are blocked. this routine should always be called last with pretend.
+ * are blocked. This routine should always be called last with pretend.
*/
static void bnx2x_vf_enable_internal(struct bnx2x *bp, u8 enable)
{
@@ -1620,7 +1620,7 @@ next_vf_to_clean:
i++)
;
- DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. num of vfs: %d\n", i,
+ DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. Num of vfs: %d\n", i,
BNX2X_NR_VIRTFN(bp));
if (i < BNX2X_NR_VIRTFN(bp)) {
@@ -1743,7 +1743,7 @@ void bnx2x_iov_init_dq(struct bnx2x *bp)
REG_WR(bp, DORQ_REG_VF_TYPE_MIN_MCID_0, 0);
REG_WR(bp, DORQ_REG_VF_TYPE_MAX_MCID_0, 0x1ffff);
- /* set the number of VF alllowed doorbells to the full DQ range */
+ /* set the number of VF allowed doorbells to the full DQ range */
REG_WR(bp, DORQ_REG_VF_NORM_MAX_CID_COUNT, 0x20000);
/* set the VF doorbell threshold */
@@ -2403,7 +2403,7 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
/* extract vf and rxq index from vf_cid - relies on the following:
* 1. vfid on cid reflects the true abs_vfid
- * 2. the max number of VFs (per path) is 64
+ * 2. The max number of VFs (per path) is 64
*/
qidx = cid & ((1 << BNX2X_VF_CID_WND)-1);
abs_vfid = (cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
@@ -2461,7 +2461,7 @@ static struct bnx2x_virtf *bnx2x_vf_by_cid(struct bnx2x *bp, int vf_cid)
{
/* extract the vf from vf_cid - relies on the following:
* 1. vfid on cid reflects the true abs_vfid
- * 2. the max number of VFs (per path) is 64
+ * 2. The max number of VFs (per path) is 64
*/
int abs_vfid = (vf_cid >> BNX2X_VF_CID_WND) & (BNX2X_MAX_NUM_OF_VFS-1);
return bnx2x_vf_by_abs_fid(bp, abs_vfid);
@@ -2480,7 +2480,7 @@ void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
if (vf) {
/* extract queue index from vf_cid - relies on the following:
* 1. vfid on cid reflects the true abs_vfid
- * 2. the max number of VFs (per path) is 64
+ * 2. The max number of VFs (per path) is 64
*/
int q_index = vf_cid & ((1 << BNX2X_VF_CID_WND)-1);
*q_obj = &bnx2x_vfq(vf, q_index, sp_obj);
@@ -2705,7 +2705,7 @@ int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
}
/* static allocation:
- * the global maximum number are fixed per VF. fail the request if
+ * the global maximum number are fixed per VF. Fail the request if
* requested number exceed these globals
*/
if (!bnx2x_vf_chk_avail_resc(bp, vf, resc)) {
@@ -2890,7 +2890,7 @@ int bnx2x_vfop_close_cmd(struct bnx2x *bp,
return -ENOMEM;
}
-/* VF release can be called either: 1. the VF was acquired but
+/* VF release can be called either: 1. The VF was acquired but
* not enabled 2. the vf was enabled or in the process of being
* enabled
*/
@@ -3024,7 +3024,6 @@ void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
{
-
struct bnx2x *bp = netdev_priv(pci_get_drvdata(dev));
DP(BNX2X_MSG_IOV, "bnx2x_sriov_configure called with %d, BNX2X_NR_VIRTFN(bp) was %d\n",
@@ -3032,7 +3031,7 @@ int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param)
/* HW channel is only operational when PF is up */
if (bp->state != BNX2X_STATE_OPEN) {
- BNX2X_ERR("VF num configurtion via sysfs not supported while PF is down");
+ BNX2X_ERR("VF num configuration via sysfs not supported while PF is down\n");
return -EINVAL;
}
@@ -3141,7 +3140,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
/* mac configured by ndo so its in bulletin board */
memcpy(&ivi->mac, bulletin->mac, ETH_ALEN);
else
- /* funtion has not been loaded yet. Show mac as 0s */
+ /* function has not been loaded yet. Show mac as 0s */
memset(&ivi->mac, 0, ETH_ALEN);
/* vlan */
@@ -3149,7 +3148,7 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
/* vlan configured by ndo so its in bulletin board */
memcpy(&ivi->vlan, &bulletin->vlan, VLAN_HLEN);
else
- /* funtion has not been loaded yet. Show vlans as 0s */
+ /* function has not been loaded yet. Show vlans as 0s */
memset(&ivi->vlan, 0, VLAN_HLEN);
}
@@ -3189,7 +3188,7 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
return -EINVAL;
}
- /* update PF's copy of the VF's bulletin. will no longer accept mac
+ /* update PF's copy of the VF's bulletin. Will no longer accept mac
* configuration requests from vf unless match this mac
*/
bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
@@ -3358,8 +3357,11 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
return 0;
}
-/* crc is the first field in the bulletin board. compute the crc over the
- * entire bulletin board excluding the crc field itself
+/* crc is the first field in the bulletin board. Compute the crc over the
+ * entire bulletin board excluding the crc field itself. Use the length field
+ * as the Bulletin Board was posted by a PF with possibly a different version
+ * from the vf which will sample it. Therefore, the length is computed by the
+ * PF and the used blindly by the VF.
*/
u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
struct pf_vf_bulletin_content *bulletin)
@@ -3389,7 +3391,7 @@ enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
&bulletin))
break;
- BNX2X_ERR("bad crc on bulletin board. contained %x computed %x\n",
+ BNX2X_ERR("bad crc on bulletin board. Contained %x computed %x\n",
bulletin.crc,
bnx2x_crc_vf_bulletin(bp, &bulletin));
}
@@ -3452,7 +3454,7 @@ int bnx2x_open_epilog(struct bnx2x *bp)
* register_netdevice which must have rtnl lock taken. As we are holding
* the lock right now, that could only work if the probe would not take
* the lock. However, as the probe of the vf may be called from other
- * contexts as well (such as passthrough to vm failes) it can't assume
+ * contexts as well (such as passthrough to vm fails) it can't assume
* the lock is being held for it. Using delayed work here allows the
* probe code to simply take the lock (i.e. wait for it to be released
* if it is being held). We only want to do this if the number of VFs
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index d67ddc5..f08c604 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -197,7 +197,7 @@ struct bnx2x_virtf {
u8 state;
#define VF_FREE 0 /* VF ready to be acquired holds no resc */
-#define VF_ACQUIRED 1 /* VF aquired, but not initalized */
+#define VF_ACQUIRED 1 /* VF acquired, but not initialized */
#define VF_ENABLED 2 /* VF Enabled */
#define VF_RESET 3 /* VF FLR'd, pending cleanup */
@@ -496,7 +496,7 @@ enum {
else if ((next) == VFOP_VERIFY_PEND) \
BNX2X_ERR("expected pending\n"); \
else { \
- DP(BNX2X_MSG_IOV, "no ramrod. scheduling\n"); \
+ DP(BNX2X_MSG_IOV, "no ramrod. Scheduling\n"); \
atomic_set(&vf->op_in_progress, 1); \
queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); \
return; \
@@ -722,7 +722,6 @@ u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
struct pf_vf_bulletin_content *bulletin);
int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf);
-
enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
/* VF side vfpf channel functions */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
index 2ca3d94..98366ab 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
@@ -1002,7 +1002,6 @@ static int bnx2x_storm_stats_update(struct bnx2x *bp)
qstats->valid_bytes_received_lo =
qstats->total_bytes_received_lo;
-
UPDATE_EXTEND_TSTAT(rcv_ucast_pkts,
total_unicast_packets_received);
UPDATE_EXTEND_TSTAT(rcv_mcast_pkts,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
index d117f47..853824d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h
@@ -40,7 +40,6 @@ struct nig_stats {
u32 egress_mac_pkt1_hi;
};
-
enum bnx2x_stats_event {
STATS_EVENT_PMF = 0,
STATS_EVENT_LINK_UP,
@@ -208,7 +207,6 @@ struct bnx2x_eth_stats {
u32 eee_tx_lpi;
};
-
struct bnx2x_eth_q_stats {
u32 total_unicast_bytes_received_hi;
u32 total_unicast_bytes_received_lo;
@@ -331,7 +329,6 @@ struct bnx2x_fw_port_stats_old {
u32 mac_discard;
};
-
/****************************************************************************
* Macros
****************************************************************************/
@@ -536,7 +533,6 @@ struct bnx2x_fw_port_stats_old {
SUB_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \
} while (0)
-
/* forward */
struct bnx2x;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index 928b074..861809d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -233,7 +233,7 @@ int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
attempts++;
- /* test whether the PF accepted our request. If not, humble the
+ /* test whether the PF accepted our request. If not, humble
* the request and try again.
*/
if (bp->acquire_resp.hdr.status == PFVF_STATUS_SUCCESS) {
@@ -333,7 +333,7 @@ int bnx2x_vfpf_release(struct bnx2x *bp)
DP(BNX2X_MSG_SP, "vf released\n");
} else {
/* PF reports error */
- BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n",
+ BNX2X_ERR("PF failed our release request - are we out of sync? Response status: %d\n",
resp->hdr.status);
rc = -EAGAIN;
goto out;
@@ -787,7 +787,7 @@ static inline void bnx2x_set_vf_mbxs_valid(struct bnx2x *bp)
storm_memset_vf_mbx_valid(bp, bnx2x_vf(bp, i, abs_vfid));
}
-/* enable vf_pf mailbox (aka vf-pf-chanell) */
+/* enable vf_pf mailbox (aka vf-pf-channel) */
void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid)
{
bnx2x_vf_flr_clnup_epilog(bp, abs_vfid);
@@ -844,7 +844,6 @@ static int bnx2x_copy32_vf_dmae(struct bnx2x *bp, u8 from_vf,
dmae.dst_addr_hi = vf_addr_hi;
}
dmae.len = len32;
- bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_DMAE);
/* issue the command and wait for completion */
return bnx2x_issue_dmae_with_comp(bp, &dmae);
@@ -1072,7 +1071,7 @@ static void bnx2x_vf_mbx_set_q_flags(struct bnx2x *bp, u32 mbx_q_flags,
if (mbx_q_flags & VFPF_QUEUE_FLG_DHC)
__set_bit(BNX2X_Q_FLG_DHC, sp_q_flags);
- /* outer vlan removal is set according to the PF's multi fuction mode */
+ /* outer vlan removal is set according to PF's multi function mode */
if (IS_MF_SD(bp))
__set_bit(BNX2X_Q_FLG_OV, sp_q_flags);
}
@@ -1104,7 +1103,7 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
struct bnx2x_queue_init_params *init_p;
struct bnx2x_queue_setup_params *setup_p;
- /* reinit the VF operation context */
+ /* re-init the VF operation context */
memset(&vf->op_params.qctor, 0 , sizeof(vf->op_params.qctor));
setup_p = &vf->op_params.qctor.prep_qsetup;
init_p = &vf->op_params.qctor.qstate.params.init;
@@ -1588,8 +1587,9 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
* support them. Or this may be because someone wrote a crappy
* VF driver and is sending garbage over the channel.
*/
- BNX2X_ERR("unknown TLV. type %d length %d. first 20 bytes of mailbox buffer:\n",
- mbx->first_tlv.tl.type, mbx->first_tlv.tl.length);
+ BNX2X_ERR("unknown TLV. type %d length %d vf->state was %d. first 20 bytes of mailbox buffer:\n",
+ mbx->first_tlv.tl.type, mbx->first_tlv.tl.length,
+ vf->state);
for (i = 0; i < 20; i++)
DP_CONT(BNX2X_MSG_IOV, "%x ",
mbx->msg->req.tlv_buf_size.tlv_buffer[i]);
@@ -1605,8 +1605,11 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
bnx2x_vf_mbx_resp(bp, vf);
} else {
/* can't send a response since this VF is unknown to us
- * just unlock the channel and be done with.
+ * just ack the FW to release the mailbox and unlock
+ * the channel.
*/
+ storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
+ mmiowb();
bnx2x_unlock_vf_pf_channel(bp, vf,
mbx->first_tlv.tl.type);
}
diff --git a/drivers/net/ethernet/broadcom/cnic.c b/drivers/net/ethernet/broadcom/cnic.c
index 6b0dc13..d78d4cf 100644
--- a/drivers/net/ethernet/broadcom/cnic.c
+++ b/drivers/net/ethernet/broadcom/cnic.c
@@ -5622,7 +5622,7 @@ static void cnic_rcv_netevent(struct cnic_local *cp, unsigned long event,
static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
- struct net_device *netdev = ptr;
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
struct cnic_dev *dev;
int new_dev = 0;
diff --git a/drivers/net/ethernet/broadcom/sb1250-mac.c b/drivers/net/ethernet/broadcom/sb1250-mac.c
index e80bfb6..c277771 100644
--- a/drivers/net/ethernet/broadcom/sb1250-mac.c
+++ b/drivers/net/ethernet/broadcom/sb1250-mac.c
@@ -2197,7 +2197,7 @@ static const struct net_device_ops sbmac_netdev_ops = {
static int sbmac_init(struct platform_device *pldev, long long base)
{
- struct net_device *dev = dev_get_drvdata(&pldev->dev);
+ struct net_device *dev = platform_get_drvdata(pldev);
int idx = pldev->id;
struct sbmac_softc *sc = netdev_priv(dev);
unsigned char *eaddr;
@@ -2275,7 +2275,7 @@ static int sbmac_init(struct platform_device *pldev, long long base)
dev->name);
goto free_mdio;
}
- dev_set_drvdata(&pldev->dev, sc->mii_bus);
+ platform_set_drvdata(pldev, sc->mii_bus);
err = register_netdev(dev);
if (err) {
@@ -2300,7 +2300,6 @@ static int sbmac_init(struct platform_device *pldev, long long base)
return 0;
unreg_mdio:
mdiobus_unregister(sc->mii_bus);
- dev_set_drvdata(&pldev->dev, NULL);
free_mdio:
mdiobus_free(sc->mii_bus);
uninit_ctx:
@@ -2624,7 +2623,7 @@ static int sbmac_probe(struct platform_device *pldev)
goto out_unmap;
}
- dev_set_drvdata(&pldev->dev, dev);
+ platform_set_drvdata(pldev, dev);
SET_NETDEV_DEV(dev, &pldev->dev);
sc = netdev_priv(dev);
@@ -2649,7 +2648,7 @@ out_out:
static int __exit sbmac_remove(struct platform_device *pldev)
{
- struct net_device *dev = dev_get_drvdata(&pldev->dev);
+ struct net_device *dev = platform_get_drvdata(pldev);
struct sbmac_softc *sc = netdev_priv(dev);
unregister_netdev(dev);
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 728d42a..986df04 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -94,10 +94,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
#define DRV_MODULE_NAME "tg3"
#define TG3_MAJ_NUM 3
-#define TG3_MIN_NUM 131
+#define TG3_MIN_NUM 132
#define DRV_MODULE_VERSION \
__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE "April 09, 2013"
+#define DRV_MODULE_RELDATE "May 21, 2013"
#define RESET_KIND_SHUTDOWN 0
#define RESET_KIND_INIT 1
@@ -965,9 +965,6 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
event = APE_EVENT_STATUS_STATE_UNLOAD;
break;
- case RESET_KIND_SUSPEND:
- event = APE_EVENT_STATUS_STATE_SUSPEND;
- break;
default:
return;
}
@@ -1314,8 +1311,8 @@ static int tg3_phy_toggle_auxctl_smdsp(struct tg3 *tp, bool enable)
if (err)
return err;
- if (enable)
+ if (enable)
val |= MII_TG3_AUXCTL_ACTL_SMDSP_ENA;
else
val &= ~MII_TG3_AUXCTL_ACTL_SMDSP_ENA;
@@ -1739,10 +1736,6 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
break;
}
}
-
- if (kind == RESET_KIND_INIT ||
- kind == RESET_KIND_SUSPEND)
- tg3_ape_driver_state_change(tp, kind);
}
/* tp->lock is held. */
@@ -1764,9 +1757,6 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
break;
}
}
-
- if (kind == RESET_KIND_SHUTDOWN)
- tg3_ape_driver_state_change(tp, kind);
}
/* tp->lock is held. */
@@ -1800,6 +1790,9 @@ static int tg3_poll_fw(struct tg3 *tp)
int i;
u32 val;
+ if (tg3_flag(tp, NO_FWARE_REPORTED))
+ return 0;
+
if (tg3_flag(tp, IS_SSB_CORE)) {
/* We don't use firmware. */
return 0;
@@ -2320,6 +2313,46 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
tg3_phy_toggle_auxctl_smdsp(tp, false);
}
+static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_eee *eee)
+{
+ u32 val;
+ struct ethtool_eee *dest = &tp->eee;
+
+ if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
+ return;
+
+ if (eee)
+ dest = eee;
+
+ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, TG3_CL45_D7_EEERES_STAT, &val))
+ return;
+
+ /* Pull eee_active */
+ if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
+ val == TG3_CL45_D7_EEERES_STAT_LP_100TX) {
+ dest->eee_active = 1;
+ } else
+ dest->eee_active = 0;
+
+ /* Pull lp advertised settings */
+ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &val))
+ return;
+ dest->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val);
+
+ /* Pull advertised and eee_enabled settings */
+ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val))
+ return;
+ dest->eee_enabled = !!val;
+ dest->advertised = mmd_eee_adv_to_ethtool_adv_t(val);
+
+ /* Pull tx_lpi_enabled */
+ val = tr32(TG3_CPMU_EEE_MODE);
+ dest->tx_lpi_enabled = !!(val & TG3_CPMU_EEEMD_LPI_IN_TX);
+
+ /* Pull lpi timer value */
+ dest->tx_lpi_timer = tr32(TG3_CPMU_EEE_DBTMR1) & 0xffff;
+}
+
static void tg3_phy_eee_adjust(struct tg3 *tp, bool current_link_up)
{
u32 val;
@@ -2343,11 +2376,8 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, bool current_link_up)
tw32(TG3_CPMU_EEE_CTRL, eeectl);
- tg3_phy_cl45_read(tp, MDIO_MMD_AN,
- TG3_CL45_D7_EEERES_STAT, &val);
-
- if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
- val == TG3_CL45_D7_EEERES_STAT_LP_100TX)
+ tg3_eee_pull_config(tp, NULL);
+ if (tp->eee.eee_active)
tp->setlpicnt = 2;
}
@@ -2957,6 +2987,31 @@ static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed)
return 0;
}
+static bool tg3_phy_power_bug(struct tg3 *tp)
+{
+ switch (tg3_asic_rev(tp)) {
+ case ASIC_REV_5700:
+ case ASIC_REV_5704:
+ return true;
+ case ASIC_REV_5780:
+ if (tp->phy_flags & TG3_PHYFLG_MII_SERDES)
+ return true;
+ return false;
+ case ASIC_REV_5717:
+ if (!tp->pci_fn)
+ return true;
+ return false;
+ case ASIC_REV_5719:
+ case ASIC_REV_5720:
+ if ((tp->phy_flags & TG3_PHYFLG_PHY_SERDES) &&
+ !tp->pci_fn)
+ return true;
+ return false;
+ }
+
+ return false;
+}
+
static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
{
u32 val;
@@ -3016,12 +3071,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
/* The PHY should not be powered down on some chips because
* of bugs.
*/
- if (tg3_asic_rev(tp) == ASIC_REV_5700 ||
- tg3_asic_rev(tp) == ASIC_REV_5704 ||
- (tg3_asic_rev(tp) == ASIC_REV_5780 &&
- (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) ||
- (tg3_asic_rev(tp) == ASIC_REV_5717 &&
- !tp->pci_fn))
+ if (tg3_phy_power_bug(tp))
return;
if (tg3_chip_rev(tp) == CHIPREV_5784_AX ||
@@ -4149,6 +4199,8 @@ static int tg3_power_down_prepare(struct tg3 *tp)
tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN);
+ tg3_ape_driver_state_change(tp, RESET_KIND_SHUTDOWN);
+
return 0;
}
@@ -4249,6 +4301,16 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
/* Advertise 1000-BaseT EEE ability */
if (advertise & ADVERTISED_1000baseT_Full)
val |= MDIO_AN_EEE_ADV_1000T;
+
+ if (!tp->eee.eee_enabled) {
+ val = 0;
+ tp->eee.advertised = 0;
+ } else {
+ tp->eee.advertised = advertise &
+ (ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full);
+ }
+
err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
if (err)
val = 0;
@@ -4493,26 +4555,23 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp)
static bool tg3_phy_eee_config_ok(struct tg3 *tp)
{
- u32 val;
- u32 tgtadv = 0;
- u32 advertising = tp->link_config.advertising;
+ struct ethtool_eee eee;
if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
return true;
- if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val))
- return false;
-
- val &= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
-
+ tg3_eee_pull_config(tp, &eee);
- if (advertising & ADVERTISED_100baseT_Full)
- tgtadv |= MDIO_AN_EEE_ADV_100TX;
- if (advertising & ADVERTISED_1000baseT_Full)
- tgtadv |= MDIO_AN_EEE_ADV_1000T;
-
- if (val != tgtadv)
- return false;
+ if (tp->eee.eee_enabled) {
+ if (tp->eee.advertised != eee.advertised ||
+ tp->eee.tx_lpi_timer != eee.tx_lpi_timer ||
+ tp->eee.tx_lpi_enabled != eee.tx_lpi_enabled)
+ return false;
+ } else {
+ /* EEE is disabled but we're advertising */
+ if (eee.advertised)
+ return false;
+ }
return true;
}
@@ -4613,6 +4672,42 @@ static void tg3_clear_mac_status(struct tg3 *tp)
udelay(40);
}
+static void tg3_setup_eee(struct tg3 *tp)
+{
+ u32 val;
+
+ val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+ TG3_CPMU_EEE_LNKIDL_UART_IDL;
+ if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
+ val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;
+
+ tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);
+
+ tw32_f(TG3_CPMU_EEE_CTRL,
+ TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
+
+ val = TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
+ (tp->eee.tx_lpi_enabled ? TG3_CPMU_EEEMD_LPI_IN_TX : 0) |
+ TG3_CPMU_EEEMD_LPI_IN_RX |
+ TG3_CPMU_EEEMD_EEE_ENABLE;
+
+ if (tg3_asic_rev(tp) != ASIC_REV_5717)
+ val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
+
+ if (tg3_flag(tp, ENABLE_APE))
+ val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;
+
+ tw32_f(TG3_CPMU_EEE_MODE, tp->eee.eee_enabled ? val : 0);
+
+ tw32_f(TG3_CPMU_EEE_DBTMR1,
+ TG3_CPMU_DBTMR1_PCIEXIT_2047US |
+ (tp->eee.tx_lpi_timer & 0xffff));
+
+ tw32_f(TG3_CPMU_EEE_DBTMR2,
+ TG3_CPMU_DBTMR2_APE_TX_2047US |
+ TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
+}
+
static int tg3_setup_copper_phy(struct tg3 *tp, bool force_reset)
{
bool current_link_up;
@@ -4779,8 +4874,10 @@ static int tg3_setup_copper_phy(struct tg3 *tp, bool force_reset)
*/
if (!eee_config_ok &&
(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
- !force_reset)
+ !force_reset) {
+ tg3_setup_eee(tp);
tg3_phy_reset(tp);
+ }
} else {
if (!(bmcr & BMCR_ANENABLE) &&
tp->link_config.speed == current_speed &&
@@ -6292,9 +6389,7 @@ static void tg3_tx_recover(struct tg3 *tp)
"Please report the problem to the driver maintainer "
"and include system chipset information.\n");
- spin_lock(&tp->lock);
tg3_flag_set(tp, TX_RECOVERY_PENDING);
- spin_unlock(&tp->lock);
}
static inline u32 tg3_tx_avail(struct tg3_napi *tnapi)
@@ -7428,6 +7523,20 @@ static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len)
return (base > 0xffffdcc0) && (base + len + 8 < base);
}
+/* Test for TSO DMA buffers that cross into regions which are within MSS bytes
+ * of any 4GB boundaries: 4G, 8G, etc
+ */
+static inline int tg3_4g_tso_overflow_test(struct tg3 *tp, dma_addr_t mapping,
+ u32 len, u32 mss)
+{
+ if (tg3_asic_rev(tp) == ASIC_REV_5762 && mss) {
+ u32 base = (u32) mapping & 0xffffffff;
+
+ return ((base + len + (mss & 0x3fff)) < base);
+ }
+ return 0;
+}
+
/* Test for DMA addresses > 40-bit */
static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping,
int len)
@@ -7464,6 +7573,9 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget,
if (tg3_4g_overflow_test(map, len))
hwbug = true;
+ if (tg3_4g_tso_overflow_test(tp, map, len, mss))
+ hwbug = true;
+
if (tg3_40bit_overflow_test(tp, map, len))
hwbug = true;
@@ -8874,6 +8986,10 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_halt_cpu(tp, RX_CPU_BASE);
}
+ err = tg3_poll_fw(tp);
+ if (err)
+ return err;
+
tw32(GRC_MODE, tp->grc_mode);
if (tg3_chip_rev_id(tp) == CHIPREV_ID_5705_A0) {
@@ -8904,10 +9020,6 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_ape_unlock(tp, TG3_APE_LOCK_GRC);
- err = tg3_poll_fw(tp);
- if (err)
- return err;
-
tg3_mdio_start(tp);
if (tg3_flag(tp, PCI_EXPRESS) &&
@@ -9129,11 +9241,9 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
}
/* tp->lock is held. */
-static void tg3_rings_reset(struct tg3 *tp)
+static void tg3_tx_rcbs_disable(struct tg3 *tp)
{
- int i;
- u32 stblk, txrcb, rxrcb, limit;
- struct tg3_napi *tnapi = &tp->napi[0];
+ u32 txrcb, limit;
/* Disable all transmit rings but the first. */
if (!tg3_flag(tp, 5705_PLUS))
@@ -9150,7 +9260,33 @@ static void tg3_rings_reset(struct tg3 *tp)
txrcb < limit; txrcb += TG3_BDINFO_SIZE)
tg3_write_mem(tp, txrcb + TG3_BDINFO_MAXLEN_FLAGS,
BDINFO_FLAGS_DISABLED);
+}
+
+/* tp->lock is held. */
+static void tg3_tx_rcbs_init(struct tg3 *tp)
+{
+ int i = 0;
+ u32 txrcb = NIC_SRAM_SEND_RCB;
+
+ if (tg3_flag(tp, ENABLE_TSS))
+ i++;
+
+ for (; i < tp->irq_max; i++, txrcb += TG3_BDINFO_SIZE) {
+ struct tg3_napi *tnapi = &tp->napi[i];
+
+ if (!tnapi->tx_ring)
+ continue;
+
+ tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping,
+ (TG3_TX_RING_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT),
+ NIC_SRAM_TX_BUFFER_DESC);
+ }
+}
+/* tp->lock is held. */
+static void tg3_rx_ret_rcbs_disable(struct tg3 *tp)
+{
+ u32 rxrcb, limit;
/* Disable all receive return rings but the first. */
if (tg3_flag(tp, 5717_PLUS))
@@ -9168,6 +9304,39 @@ static void tg3_rings_reset(struct tg3 *tp)
rxrcb < limit; rxrcb += TG3_BDINFO_SIZE)
tg3_write_mem(tp, rxrcb + TG3_BDINFO_MAXLEN_FLAGS,
BDINFO_FLAGS_DISABLED);
+}
+
+/* tp->lock is held. */
+static void tg3_rx_ret_rcbs_init(struct tg3 *tp)
+{
+ int i = 0;
+ u32 rxrcb = NIC_SRAM_RCV_RET_RCB;
+
+ if (tg3_flag(tp, ENABLE_RSS))
+ i++;
+
+ for (; i < tp->irq_max; i++, rxrcb += TG3_BDINFO_SIZE) {
+ struct tg3_napi *tnapi = &tp->napi[i];
+
+ if (!tnapi->rx_rcb)
+ continue;
+
+ tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping,
+ (tp->rx_ret_ring_mask + 1) <<
+ BDINFO_FLAGS_MAXLEN_SHIFT, 0);
+ }
+}
+
+/* tp->lock is held. */
+static void tg3_rings_reset(struct tg3 *tp)
+{
+ int i;
+ u32 stblk;
+ struct tg3_napi *tnapi = &tp->napi[0];
+
+ tg3_tx_rcbs_disable(tp);
+
+ tg3_rx_ret_rcbs_disable(tp);
/* Disable interrupts */
tw32_mailbox_f(tp->napi[0].int_mbox, 1);
@@ -9204,9 +9373,6 @@ static void tg3_rings_reset(struct tg3 *tp)
tw32_tx_mbox(mbox + i * 8, 0);
}
- txrcb = NIC_SRAM_SEND_RCB;
- rxrcb = NIC_SRAM_RCV_RET_RCB;
-
/* Clear status block in ram. */
memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE);
@@ -9216,46 +9382,20 @@ static void tg3_rings_reset(struct tg3 *tp)
tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_LOW,
((u64) tnapi->status_mapping & 0xffffffff));
- if (tnapi->tx_ring) {
- tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping,
- (TG3_TX_RING_SIZE <<
- BDINFO_FLAGS_MAXLEN_SHIFT),
- NIC_SRAM_TX_BUFFER_DESC);
- txrcb += TG3_BDINFO_SIZE;
- }
-
- if (tnapi->rx_rcb) {
- tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping,
- (tp->rx_ret_ring_mask + 1) <<
- BDINFO_FLAGS_MAXLEN_SHIFT, 0);
- rxrcb += TG3_BDINFO_SIZE;
- }
-
stblk = HOSTCC_STATBLCK_RING1;
for (i = 1, tnapi++; i < tp->irq_cnt; i++, tnapi++) {
u64 mapping = (u64)tnapi->status_mapping;
tw32(stblk + TG3_64BIT_REG_HIGH, mapping >> 32);
tw32(stblk + TG3_64BIT_REG_LOW, mapping & 0xffffffff);
+ stblk += 8;
/* Clear status block in ram. */
memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE);
-
- if (tnapi->tx_ring) {
- tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping,
- (TG3_TX_RING_SIZE <<
- BDINFO_FLAGS_MAXLEN_SHIFT),
- NIC_SRAM_TX_BUFFER_DESC);
- txrcb += TG3_BDINFO_SIZE;
- }
-
- tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping,
- ((tp->rx_ret_ring_mask + 1) <<
- BDINFO_FLAGS_MAXLEN_SHIFT), 0);
-
- stblk += 8;
- rxrcb += TG3_BDINFO_SIZE;
}
+
+ tg3_tx_rcbs_init(tp);
+ tg3_rx_ret_rcbs_init(tp);
}
static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
@@ -9431,6 +9571,14 @@ static void tg3_rss_write_indir_tbl(struct tg3 *tp)
}
}
+static inline u32 tg3_lso_rd_dma_workaround_bit(struct tg3 *tp)
+{
+ if (tg3_asic_rev(tp) == ASIC_REV_5719)
+ return TG3_LSO_RD_DMA_TX_LENGTH_WA_5719;
+ else
+ return TG3_LSO_RD_DMA_TX_LENGTH_WA_5720;
+}
+
/* tp->lock is held. */
static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
{
@@ -9447,46 +9595,17 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
if (tg3_flag(tp, INIT_COMPLETE))
tg3_abort_hw(tp, 1);
- /* Enable MAC control of LPI */
- if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
- val = TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
- TG3_CPMU_EEE_LNKIDL_UART_IDL;
- if (tg3_chip_rev_id(tp) == CHIPREV_ID_57765_A0)
- val |= TG3_CPMU_EEE_LNKIDL_APE_TX_MT;
-
- tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL, val);
-
- tw32_f(TG3_CPMU_EEE_CTRL,
- TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
-
- val = TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
- TG3_CPMU_EEEMD_LPI_IN_TX |
- TG3_CPMU_EEEMD_LPI_IN_RX |
- TG3_CPMU_EEEMD_EEE_ENABLE;
-
- if (tg3_asic_rev(tp) != ASIC_REV_5717)
- val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
-
- if (tg3_flag(tp, ENABLE_APE))
- val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;
-
- tw32_f(TG3_CPMU_EEE_MODE, val);
-
- tw32_f(TG3_CPMU_EEE_DBTMR1,
- TG3_CPMU_DBTMR1_PCIEXIT_2047US |
- TG3_CPMU_DBTMR1_LNKIDLE_2047US);
-
- tw32_f(TG3_CPMU_EEE_DBTMR2,
- TG3_CPMU_DBTMR2_APE_TX_2047US |
- TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
- }
-
if ((tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
!(tp->phy_flags & TG3_PHYFLG_USER_CONFIGURED)) {
tg3_phy_pull_config(tp);
+ tg3_eee_pull_config(tp, NULL);
tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
}
+ /* Enable MAC control of LPI */
+ if (tp->phy_flags & TG3_PHYFLG_EEE_CAP)
+ tg3_setup_eee(tp);
+
if (reset_phy)
tg3_phy_reset(tp);
@@ -10116,16 +10235,17 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
tw32_f(RDMAC_MODE, rdmac_mode);
udelay(40);
- if (tg3_asic_rev(tp) == ASIC_REV_5719) {
+ if (tg3_asic_rev(tp) == ASIC_REV_5719 ||
+ tg3_asic_rev(tp) == ASIC_REV_5720) {
for (i = 0; i < TG3_NUM_RDMA_CHANNELS; i++) {
if (tr32(TG3_RDMA_LENGTH + (i << 2)) > TG3_MAX_MTU(tp))
break;
}
if (i < TG3_NUM_RDMA_CHANNELS) {
val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
- val |= TG3_LSO_RD_DMA_TX_LENGTH_WA;
+ val |= tg3_lso_rd_dma_workaround_bit(tp);
tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val);
- tg3_flag_set(tp, 5719_RDMA_BUG);
+ tg3_flag_set(tp, 5719_5720_RDMA_BUG);
}
}
@@ -10358,6 +10478,13 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
*/
static int tg3_init_hw(struct tg3 *tp, bool reset_phy)
{
+ /* Chip may have been just powered on. If so, the boot code may still
+ * be running initialization. Wait for it to finish to avoid races in
+ * accessing the hardware.
+ */
+ tg3_enable_register_access(tp);
+ tg3_poll_fw(tp);
+
tg3_switch_clocks(tp);
tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
@@ -10489,15 +10616,15 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp)
TG3_STAT_ADD32(&sp->tx_ucast_packets, MAC_TX_STATS_UCAST);
TG3_STAT_ADD32(&sp->tx_mcast_packets, MAC_TX_STATS_MCAST);
TG3_STAT_ADD32(&sp->tx_bcast_packets, MAC_TX_STATS_BCAST);
- if (unlikely(tg3_flag(tp, 5719_RDMA_BUG) &&
+ if (unlikely(tg3_flag(tp, 5719_5720_RDMA_BUG) &&
(sp->tx_ucast_packets.low + sp->tx_mcast_packets.low +
sp->tx_bcast_packets.low) > TG3_NUM_RDMA_CHANNELS)) {
u32 val;
val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
- val &= ~TG3_LSO_RD_DMA_TX_LENGTH_WA;
+ val &= ~tg3_lso_rd_dma_workaround_bit(tp);
tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val);
- tg3_flag_clear(tp, 5719_RDMA_BUG);
+ tg3_flag_clear(tp, 5719_5720_RDMA_BUG);
}
TG3_STAT_ADD32(&sp->rx_octets, MAC_RX_STATS_OCTETS);
@@ -11134,7 +11261,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
*/
err = tg3_alloc_consistent(tp);
if (err)
- goto err_out1;
+ goto out_ints_fini;
tg3_napi_init(tp);
@@ -11148,12 +11275,15 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
tnapi = &tp->napi[i];
free_irq(tnapi->irq_vec, tnapi);
}
- goto err_out2;
+ goto out_napi_fini;
}
}
tg3_full_lock(tp, 0);
+ if (init)
+ tg3_ape_driver_state_change(tp, RESET_KIND_INIT);
+
err = tg3_init_hw(tp, reset_phy);
if (err) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
@@ -11163,7 +11293,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
tg3_full_unlock(tp);
if (err)
- goto err_out3;
+ goto out_free_irq;
if (test_irq && tg3_flag(tp, USING_MSI)) {
err = tg3_test_msi(tp);
@@ -11174,7 +11304,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
tg3_free_rings(tp);
tg3_full_unlock(tp);
- goto err_out2;
+ goto out_napi_fini;
}
if (!tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) {
@@ -11214,18 +11344,18 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
return 0;
-err_out3:
+out_free_irq:
for (i = tp->irq_cnt - 1; i >= 0; i--) {
struct tg3_napi *tnapi = &tp->napi[i];
free_irq(tnapi->irq_vec, tnapi);
}
-err_out2:
+out_napi_fini:
tg3_napi_disable(tp);
tg3_napi_fini(tp);
tg3_free_consistent(tp);
-err_out1:
+out_ints_fini:
tg3_ints_fini(tp);
return err;
@@ -13270,11 +13400,13 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
struct tg3 *tp = netdev_priv(dev);
bool doextlpbk = etest->flags & ETH_TEST_FL_EXTERNAL_LB;
- if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) &&
- tg3_power_up(tp)) {
- etest->flags |= ETH_TEST_FL_FAILED;
- memset(data, 1, sizeof(u64) * TG3_NUM_TEST);
- return;
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+ if (tg3_power_up(tp)) {
+ etest->flags |= ETH_TEST_FL_FAILED;
+ memset(data, 1, sizeof(u64) * TG3_NUM_TEST);
+ return;
+ }
+ tg3_ape_driver_state_change(tp, RESET_KIND_INIT);
}
memset(data, 0, sizeof(u64) * TG3_NUM_TEST);
@@ -13565,6 +13697,57 @@ static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
return 0;
}
+static int tg3_set_eee(struct net_device *dev, struct ethtool_eee *edata)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
+ netdev_warn(tp->dev, "Board does not support EEE!\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (edata->advertised != tp->eee.advertised) {
+ netdev_warn(tp->dev,
+ "Direct manipulation of EEE advertisement is not supported\n");
+ return -EINVAL;
+ }
+
+ if (edata->tx_lpi_timer > TG3_CPMU_DBTMR1_LNKIDLE_MAX) {
+ netdev_warn(tp->dev,
+ "Maximal Tx Lpi timer supported is %#x(u)\n",
+ TG3_CPMU_DBTMR1_LNKIDLE_MAX);
+ return -EINVAL;
+ }
+
+ tp->eee = *edata;
+
+ tp->phy_flags |= TG3_PHYFLG_USER_CONFIGURED;
+ tg3_warn_mgmt_link_flap(tp);
+
+ if (netif_running(tp->dev)) {
+ tg3_full_lock(tp, 0);
+ tg3_setup_eee(tp);
+ tg3_phy_reset(tp);
+ tg3_full_unlock(tp);
+ }
+
+ return 0;
+}
+
+static int tg3_get_eee(struct net_device *dev, struct ethtool_eee *edata)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) {
+ netdev_warn(tp->dev,
+ "Board does not support EEE!\n");
+ return -EOPNOTSUPP;
+ }
+
+ *edata = tp->eee;
+ return 0;
+}
+
static const struct ethtool_ops tg3_ethtool_ops = {
.get_settings = tg3_get_settings,
.set_settings = tg3_set_settings,
@@ -13598,6 +13781,8 @@ static const struct ethtool_ops tg3_ethtool_ops = {
.get_channels = tg3_get_channels,
.set_channels = tg3_set_channels,
.get_ts_info = tg3_get_ts_info,
+ .get_eee = tg3_get_eee,
+ .set_eee = tg3_set_eee,
};
static struct rtnl_link_stats64 *tg3_get_stats64(struct net_device *dev,
@@ -14946,9 +15131,18 @@ static int tg3_phy_probe(struct tg3 *tp)
(tg3_asic_rev(tp) == ASIC_REV_5717 &&
tg3_chip_rev_id(tp) != CHIPREV_ID_5717_A0) ||
(tg3_asic_rev(tp) == ASIC_REV_57765 &&
- tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0)))
+ tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0))) {
tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
+ tp->eee.supported = SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Full;
+ tp->eee.advertised = ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full;
+ tp->eee.eee_enabled = 1;
+ tp->eee.tx_lpi_enabled = 1;
+ tp->eee.tx_lpi_timer = TG3_CPMU_DBTMR1_LNKIDLE_2047US;
+ }
+
tg3_phy_init_link_config(tp);
if (!(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN) &&
@@ -17020,7 +17214,7 @@ static int tg3_init_one(struct pci_dev *pdev,
{
struct net_device *dev;
struct tg3 *tp;
- int i, err, pm_cap;
+ int i, err;
u32 sndmbx, rcvmbx, intmbx;
char str[40];
u64 dma_mask, persist_dma_mask;
@@ -17042,25 +17236,10 @@ static int tg3_init_one(struct pci_dev *pdev,
pci_set_master(pdev);
- /* Find power-management capability. */
- pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pm_cap == 0) {
- dev_err(&pdev->dev,
- "Cannot find Power Management capability, aborting\n");
- err = -EIO;
- goto err_out_free_res;
- }
-
- err = pci_set_power_state(pdev, PCI_D0);
- if (err) {
- dev_err(&pdev->dev, "Transition to D0 failed, aborting\n");
- goto err_out_free_res;
- }
-
dev = alloc_etherdev_mq(sizeof(*tp), TG3_IRQ_MAX_VECS);
if (!dev) {
err = -ENOMEM;
- goto err_out_power_down;
+ goto err_out_free_res;
}
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -17068,7 +17247,7 @@ static int tg3_init_one(struct pci_dev *pdev,
tp = netdev_priv(dev);
tp->pdev = pdev;
tp->dev = dev;
- tp->pm_cap = pm_cap;
+ tp->pm_cap = pdev->pm_cap;
tp->rx_mode = TG3_DEF_RX_MODE;
tp->tx_mode = TG3_DEF_TX_MODE;
tp->irq_sync = 1;
@@ -17406,9 +17585,6 @@ err_out_iounmap:
err_out_free_dev:
free_netdev(dev);
-err_out_power_down:
- pci_set_power_state(pdev, PCI_D3hot);
-
err_out_free_res:
pci_release_regions(pdev);
@@ -17518,6 +17694,8 @@ static int tg3_resume(struct device *device)
tg3_full_lock(tp, 0);
+ tg3_ape_driver_state_change(tp, RESET_KIND_INIT);
+
tg3_flag_set(tp, INIT_COMPLETE);
err = tg3_restart_hw(tp,
!(tp->phy_flags & TG3_PHYFLG_KEEP_LINK_ON_PWRDN));
@@ -17579,10 +17757,13 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
tg3_full_unlock(tp);
done:
- if (state == pci_channel_io_perm_failure)
+ if (state == pci_channel_io_perm_failure) {
+ tg3_napi_enable(tp);
+ dev_close(netdev);
err = PCI_ERS_RESULT_DISCONNECT;
- else
+ } else {
pci_disable_device(pdev);
+ }
rtnl_unlock();
@@ -17628,6 +17809,10 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
rc = PCI_ERS_RESULT_RECOVERED;
done:
+ if (rc != PCI_ERS_RESULT_RECOVERED && netif_running(netdev)) {
+ tg3_napi_enable(tp);
+ dev_close(netdev);
+ }
rtnl_unlock();
return rc;
@@ -17652,6 +17837,7 @@ static void tg3_io_resume(struct pci_dev *pdev)
goto done;
tg3_full_lock(tp, 0);
+ tg3_ape_driver_state_change(tp, RESET_KIND_INIT);
tg3_flag_set(tp, INIT_COMPLETE);
err = tg3_restart_hw(tp, true);
if (err) {
@@ -17689,15 +17875,4 @@ static struct pci_driver tg3_driver = {
.driver.pm = &tg3_pm_ops,
};
-static int __init tg3_init(void)
-{
- return pci_register_driver(&tg3_driver);
-}
-
-static void __exit tg3_cleanup(void)
-{
- pci_unregister_driver(&tg3_driver);
-}
-
-module_init(tg3_init);
-module_exit(tg3_cleanup);
+module_pci_driver(tg3_driver);
diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h
index 9b2d3ac..cd63d11 100644
--- a/drivers/net/ethernet/broadcom/tg3.h
+++ b/drivers/net/ethernet/broadcom/tg3.h
@@ -1175,6 +1175,7 @@
#define TG3_CPMU_EEE_DBTMR1 0x000036b4
#define TG3_CPMU_DBTMR1_PCIEXIT_2047US 0x07ff0000
#define TG3_CPMU_DBTMR1_LNKIDLE_2047US 0x000007ff
+#define TG3_CPMU_DBTMR1_LNKIDLE_MAX 0x0000ffff
#define TG3_CPMU_EEE_DBTMR2 0x000036b8
#define TG3_CPMU_DBTMR2_APE_TX_2047US 0x07ff0000
#define TG3_CPMU_DBTMR2_TXIDXEQ_2047US 0x000007ff
@@ -1422,7 +1423,8 @@
#define TG3_LSO_RD_DMA_CRPTEN_CTRL 0x00004910
#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K 0x00030000
#define TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_LSO_4K 0x000c0000
-#define TG3_LSO_RD_DMA_TX_LENGTH_WA 0x02000000
+#define TG3_LSO_RD_DMA_TX_LENGTH_WA_5719 0x02000000
+#define TG3_LSO_RD_DMA_TX_LENGTH_WA_5720 0x00200000
/* 0x4914 --> 0x4be0 unused */
#define TG3_NUM_RDMA_CHANNELS 4
@@ -3059,7 +3061,7 @@ enum TG3_FLAGS {
TG3_FLAG_APE_HAS_NCSI,
TG3_FLAG_TX_TSTAMP_EN,
TG3_FLAG_4K_FIFO_LIMIT,
- TG3_FLAG_5719_RDMA_BUG,
+ TG3_FLAG_5719_5720_RDMA_BUG,
TG3_FLAG_RESET_TASK_PENDING,
TG3_FLAG_PTP_CAPABLE,
TG3_FLAG_5705_PLUS,
@@ -3371,6 +3373,7 @@ struct tg3 {
unsigned int irq_cnt;
struct ethtool_coalesce coal;
+ struct ethtool_eee eee;
/* firmware info */
const char *fw_needed;
diff --git a/drivers/net/ethernet/brocade/bna/bfa_defs.h b/drivers/net/ethernet/brocade/bna/bfa_defs.h
index e423f82..b7d8127 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_defs.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_defs.h
@@ -164,7 +164,8 @@ struct bfa_ioc_attr {
u8 port_mode; /*!< enum bfa_mode */
u8 cap_bm; /*!< capability */
u8 port_mode_cfg; /*!< enum bfa_mode */
- u8 rsvd[4]; /*!< 64bit align */
+ u8 def_fn; /*!< 1 if default fn */
+ u8 rsvd[3]; /*!< 64bit align */
};
/* Adapter capability mask definition */
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index f2b73ff..6f3cac0 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -2371,7 +2371,7 @@ bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr)
memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr));
ioc_attr->state = bfa_ioc_get_state(ioc);
- ioc_attr->port_id = ioc->port_id;
+ ioc_attr->port_id = bfa_ioc_portid(ioc);
ioc_attr->port_mode = ioc->port_mode;
ioc_attr->port_mode_cfg = ioc->port_mode_cfg;
@@ -2381,8 +2381,9 @@ bfa_nw_ioc_get_attr(struct bfa_ioc *ioc, struct bfa_ioc_attr *ioc_attr)
bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
- ioc_attr->pci_attr.device_id = ioc->pcidev.device_id;
- ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func;
+ ioc_attr->pci_attr.device_id = bfa_ioc_devid(ioc);
+ ioc_attr->pci_attr.pcifn = bfa_ioc_pcifn(ioc);
+ ioc_attr->def_fn = bfa_ioc_is_default(ioc);
bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev);
}
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.h b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
index 63a85e5..f04e0aa 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.h
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.h
@@ -222,6 +222,8 @@ struct bfa_ioc_hwif {
#define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva)
#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
#define bfa_ioc_asic_gen(__ioc) ((__ioc)->asic_gen)
+#define bfa_ioc_is_default(__ioc) \
+ (bfa_ioc_pcifn(__ioc) == bfa_ioc_portid(__ioc))
#define bfa_ioc_fetch_stats(__ioc, __stats) \
(((__stats)->drv_stats) = (__ioc)->stats)
#define bfa_ioc_clr_stats(__ioc) \
diff --git a/drivers/net/ethernet/brocade/bna/bna.h b/drivers/net/ethernet/brocade/bna/bna.h
index 25dae75..f1eafc4 100644
--- a/drivers/net/ethernet/brocade/bna/bna.h
+++ b/drivers/net/ethernet/brocade/bna/bna.h
@@ -455,6 +455,8 @@ void bna_bfi_rx_enet_stop_rsp(struct bna_rx *rx,
void bna_bfi_rxf_cfg_rsp(struct bna_rxf *rxf, struct bfi_msgq_mhdr *msghdr);
void bna_bfi_rxf_mcast_add_rsp(struct bna_rxf *rxf,
struct bfi_msgq_mhdr *msghdr);
+void bna_bfi_rxf_ucast_set_rsp(struct bna_rxf *rxf,
+ struct bfi_msgq_mhdr *msghdr);
/* APIs for BNA */
void bna_rx_mod_init(struct bna_rx_mod *rx_mod, struct bna *bna,
diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c
index db14f69..3ca77fa 100644
--- a/drivers/net/ethernet/brocade/bna/bna_enet.c
+++ b/drivers/net/ethernet/brocade/bna/bna_enet.c
@@ -298,7 +298,6 @@ bna_msgq_rsp_handler(void *arg, struct bfi_msgq_mhdr *msghdr)
case BFI_ENET_I2H_RSS_ENABLE_RSP:
case BFI_ENET_I2H_RX_PROMISCUOUS_RSP:
case BFI_ENET_I2H_RX_DEFAULT_RSP:
- case BFI_ENET_I2H_MAC_UCAST_SET_RSP:
case BFI_ENET_I2H_MAC_UCAST_CLR_RSP:
case BFI_ENET_I2H_MAC_UCAST_ADD_RSP:
case BFI_ENET_I2H_MAC_UCAST_DEL_RSP:
@@ -311,6 +310,12 @@ bna_msgq_rsp_handler(void *arg, struct bfi_msgq_mhdr *msghdr)
bna_bfi_rxf_cfg_rsp(&rx->rxf, msghdr);
break;
+ case BFI_ENET_I2H_MAC_UCAST_SET_RSP:
+ bna_rx_from_rid(bna, msghdr->enet_id, rx);
+ if (rx)
+ bna_bfi_rxf_ucast_set_rsp(&rx->rxf, msghdr);
+ break;
+
case BFI_ENET_I2H_MAC_MCAST_ADD_RSP:
bna_rx_from_rid(bna, msghdr->enet_id, rx);
if (rx)
diff --git a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
index ea6f4a0..57cd1bf 100644
--- a/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
+++ b/drivers/net/ethernet/brocade/bna/bna_tx_rx.c
@@ -711,6 +711,21 @@ bna_bfi_rxf_cfg_rsp(struct bna_rxf *rxf, struct bfi_msgq_mhdr *msghdr)
}
void
+bna_bfi_rxf_ucast_set_rsp(struct bna_rxf *rxf,
+ struct bfi_msgq_mhdr *msghdr)
+{
+ struct bfi_enet_rsp *rsp =
+ (struct bfi_enet_rsp *)msghdr;
+
+ if (rsp->error) {
+ /* Clear ucast from cache */
+ rxf->ucast_active_set = 0;
+ }
+
+ bfa_fsm_send_event(rxf, RXF_E_FW_RESP);
+}
+
+void
bna_bfi_rxf_mcast_add_rsp(struct bna_rxf *rxf,
struct bfi_msgq_mhdr *msghdr)
{
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index ce4a030..b78e69e 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -2624,6 +2624,9 @@ bnad_stop(struct net_device *netdev)
bnad_destroy_tx(bnad, 0);
bnad_destroy_rx(bnad, 0);
+ /* These config flags are cleared in the hardware */
+ bnad->cfg_flags &= ~(BNAD_CF_ALLMULTI | BNAD_CF_PROMISC);
+
/* Synchronize mailbox IRQ */
bnad_mbox_irq_sync(bnad);
@@ -3236,9 +3239,10 @@ bnad_init(struct bnad *bnad,
sprintf(bnad->wq_name, "%s_wq_%d", BNAD_NAME, bnad->id);
bnad->work_q = create_singlethread_workqueue(bnad->wq_name);
-
- if (!bnad->work_q)
+ if (!bnad->work_q) {
+ iounmap(bnad->bar0);
return -ENOMEM;
+ }
return 0;
}
diff --git a/drivers/net/ethernet/brocade/bna/bnad.h b/drivers/net/ethernet/brocade/bna/bnad.h
index c1d0bc0..aefee77 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.h
+++ b/drivers/net/ethernet/brocade/bna/bnad.h
@@ -71,7 +71,7 @@ struct bnad_rx_ctrl {
#define BNAD_NAME "bna"
#define BNAD_NAME_LEN 64
-#define BNAD_VERSION "3.1.2.1"
+#define BNAD_VERSION "3.2.21.1"
#define BNAD_MAILBOX_MSIX_INDEX 0
#define BNAD_MAILBOX_MSIX_VECTORS 1
diff --git a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
index 6e8bc9d..94d957d 100644
--- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
+++ b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c
@@ -244,7 +244,7 @@ bnad_debugfs_lseek(struct file *file, loff_t offset, int orig)
file->f_pos += offset;
break;
case 2:
- file->f_pos = debug->buffer_len - offset;
+ file->f_pos = debug->buffer_len + offset;
break;
default:
return -EINVAL;
diff --git a/drivers/net/ethernet/brocade/bna/cna.h b/drivers/net/ethernet/brocade/bna/cna.h
index 14ca931..c37f706 100644
--- a/drivers/net/ethernet/brocade/bna/cna.h
+++ b/drivers/net/ethernet/brocade/bna/cna.h
@@ -37,8 +37,8 @@
extern char bfa_version[];
-#define CNA_FW_FILE_CT "ctfw-3.1.0.0.bin"
-#define CNA_FW_FILE_CT2 "ct2fw-3.1.0.0.bin"
+#define CNA_FW_FILE_CT "ctfw-3.2.1.0.bin"
+#define CNA_FW_FILE_CT2 "ct2fw-3.2.1.0.bin"
#define FC_SYMNAME_MAX 256 /*!< max name server symbolic name size */
#pragma pack(1)
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index 1194446..8030cc0 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -22,8 +22,7 @@ if NET_CADENCE
config ARM_AT91_ETHER
tristate "AT91RM9200 Ethernet support"
- depends on GENERIC_HARDIRQS
- select NET_CORE
+ depends on GENERIC_HARDIRQS && HAS_DMA
select MACB
---help---
If you wish to compile a kernel for the AT91RM9200 and enable
@@ -31,6 +30,7 @@ config ARM_AT91_ETHER
config MACB
tristate "Cadence MACB/GEM support"
+ depends on HAS_DMA
select PHYLIB
---help---
The Cadence MACB ethernet interface is found on many Atmel AT32 and
diff --git a/drivers/net/ethernet/cadence/at91_ether.c b/drivers/net/ethernet/cadence/at91_ether.c
index cc9a185..3f19571 100644
--- a/drivers/net/ethernet/cadence/at91_ether.c
+++ b/drivers/net/ethernet/cadence/at91_ether.c
@@ -435,7 +435,6 @@ static int at91ether_remove(struct platform_device *pdev)
unregister_netdev(dev);
clk_disable(lp->pclk);
free_netdev(dev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 6be513d..f7e21f2 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -32,7 +32,8 @@
#include "macb.h"
-#define RX_BUFFER_SIZE 128
+#define MACB_RX_BUFFER_SIZE 128
+#define RX_BUFFER_MULTIPLE 64 /* bytes */
#define RX_RING_SIZE 512 /* must be power of 2 */
#define RX_RING_BYTES (sizeof(struct macb_dma_desc) * RX_RING_SIZE)
@@ -92,7 +93,7 @@ static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
static void *macb_rx_buffer(struct macb *bp, unsigned int index)
{
- return bp->rx_buffers + RX_BUFFER_SIZE * macb_rx_ring_wrap(index);
+ return bp->rx_buffers + bp->rx_buffer_size * macb_rx_ring_wrap(index);
}
void macb_set_hwaddr(struct macb *bp)
@@ -485,7 +486,8 @@ static void macb_tx_interrupt(struct macb *bp)
status = macb_readl(bp, TSR);
macb_writel(bp, TSR, status);
- macb_writel(bp, ISR, MACB_BIT(TCOMP));
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ macb_writel(bp, ISR, MACB_BIT(TCOMP));
netdev_vdbg(bp->dev, "macb_tx_interrupt status = 0x%03lx\n",
(unsigned long)status);
@@ -527,6 +529,155 @@ static void macb_tx_interrupt(struct macb *bp)
netif_wake_queue(bp->dev);
}
+static void gem_rx_refill(struct macb *bp)
+{
+ unsigned int entry;
+ struct sk_buff *skb;
+ struct macb_dma_desc *desc;
+ dma_addr_t paddr;
+
+ while (CIRC_SPACE(bp->rx_prepared_head, bp->rx_tail, RX_RING_SIZE) > 0) {
+ u32 addr, ctrl;
+
+ entry = macb_rx_ring_wrap(bp->rx_prepared_head);
+ desc = &bp->rx_ring[entry];
+
+ /* Make hw descriptor updates visible to CPU */
+ rmb();
+
+ addr = desc->addr;
+ ctrl = desc->ctrl;
+ bp->rx_prepared_head++;
+
+ if ((addr & MACB_BIT(RX_USED)))
+ continue;
+
+ if (bp->rx_skbuff[entry] == NULL) {
+ /* allocate sk_buff for this free entry in ring */
+ skb = netdev_alloc_skb(bp->dev, bp->rx_buffer_size);
+ if (unlikely(skb == NULL)) {
+ netdev_err(bp->dev,
+ "Unable to allocate sk_buff\n");
+ break;
+ }
+ bp->rx_skbuff[entry] = skb;
+
+ /* now fill corresponding descriptor entry */
+ paddr = dma_map_single(&bp->pdev->dev, skb->data,
+ bp->rx_buffer_size, DMA_FROM_DEVICE);
+
+ if (entry == RX_RING_SIZE - 1)
+ paddr |= MACB_BIT(RX_WRAP);
+ bp->rx_ring[entry].addr = paddr;
+ bp->rx_ring[entry].ctrl = 0;
+
+ /* properly align Ethernet header */
+ skb_reserve(skb, NET_IP_ALIGN);
+ }
+ }
+
+ /* Make descriptor updates visible to hardware */
+ wmb();
+
+ netdev_vdbg(bp->dev, "rx ring: prepared head %d, tail %d\n",
+ bp->rx_prepared_head, bp->rx_tail);
+}
+
+/* Mark DMA descriptors from begin up to and not including end as unused */
+static void discard_partial_frame(struct macb *bp, unsigned int begin,
+ unsigned int end)
+{
+ unsigned int frag;
+
+ for (frag = begin; frag != end; frag++) {
+ struct macb_dma_desc *desc = macb_rx_desc(bp, frag);
+ desc->addr &= ~MACB_BIT(RX_USED);
+ }
+
+ /* Make descriptor updates visible to hardware */
+ wmb();
+
+ /*
+ * When this happens, the hardware stats registers for
+ * whatever caused this is updated, so we don't have to record
+ * anything.
+ */
+}
+
+static int gem_rx(struct macb *bp, int budget)
+{
+ unsigned int len;
+ unsigned int entry;
+ struct sk_buff *skb;
+ struct macb_dma_desc *desc;
+ int count = 0;
+
+ while (count < budget) {
+ u32 addr, ctrl;
+
+ entry = macb_rx_ring_wrap(bp->rx_tail);
+ desc = &bp->rx_ring[entry];
+
+ /* Make hw descriptor updates visible to CPU */
+ rmb();
+
+ addr = desc->addr;
+ ctrl = desc->ctrl;
+
+ if (!(addr & MACB_BIT(RX_USED)))
+ break;
+
+ desc->addr &= ~MACB_BIT(RX_USED);
+ bp->rx_tail++;
+ count++;
+
+ if (!(ctrl & MACB_BIT(RX_SOF) && ctrl & MACB_BIT(RX_EOF))) {
+ netdev_err(bp->dev,
+ "not whole frame pointed by descriptor\n");
+ bp->stats.rx_dropped++;
+ break;
+ }
+ skb = bp->rx_skbuff[entry];
+ if (unlikely(!skb)) {
+ netdev_err(bp->dev,
+ "inconsistent Rx descriptor chain\n");
+ bp->stats.rx_dropped++;
+ break;
+ }
+ /* now everything is ready for receiving packet */
+ bp->rx_skbuff[entry] = NULL;
+ len = MACB_BFEXT(RX_FRMLEN, ctrl);
+
+ netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len);
+
+ skb_put(skb, len);
+ addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, addr));
+ dma_unmap_single(&bp->pdev->dev, addr,
+ len, DMA_FROM_DEVICE);
+
+ skb->protocol = eth_type_trans(skb, bp->dev);
+ skb_checksum_none_assert(skb);
+
+ bp->stats.rx_packets++;
+ bp->stats.rx_bytes += skb->len;
+
+#if defined(DEBUG) && defined(VERBOSE_DEBUG)
+ netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
+ skb->len, skb->csum);
+ print_hex_dump(KERN_DEBUG, " mac: ", DUMP_PREFIX_ADDRESS, 16, 1,
+ skb->mac_header, 16, true);
+ print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_ADDRESS, 16, 1,
+ skb->data, 32, true);
+#endif
+
+ netif_receive_skb(skb);
+ }
+
+ gem_rx_refill(bp);
+
+ return count;
+}
+
static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
unsigned int last_frag)
{
@@ -574,7 +725,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
skb_put(skb, len);
for (frag = first_frag; ; frag++) {
- unsigned int frag_len = RX_BUFFER_SIZE;
+ unsigned int frag_len = bp->rx_buffer_size;
if (offset + frag_len > len) {
BUG_ON(frag != last_frag);
@@ -582,7 +733,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
}
skb_copy_to_linear_data_offset(skb, offset,
macb_rx_buffer(bp, frag), frag_len);
- offset += RX_BUFFER_SIZE;
+ offset += bp->rx_buffer_size;
desc = macb_rx_desc(bp, frag);
desc->addr &= ~MACB_BIT(RX_USED);
@@ -605,27 +756,6 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
return 0;
}
-/* Mark DMA descriptors from begin up to and not including end as unused */
-static void discard_partial_frame(struct macb *bp, unsigned int begin,
- unsigned int end)
-{
- unsigned int frag;
-
- for (frag = begin; frag != end; frag++) {
- struct macb_dma_desc *desc = macb_rx_desc(bp, frag);
- desc->addr &= ~MACB_BIT(RX_USED);
- }
-
- /* Make descriptor updates visible to hardware */
- wmb();
-
- /*
- * When this happens, the hardware stats registers for
- * whatever caused this is updated, so we don't have to record
- * anything.
- */
-}
-
static int macb_rx(struct macb *bp, int budget)
{
int received = 0;
@@ -686,7 +816,7 @@ static int macb_poll(struct napi_struct *napi, int budget)
netdev_vdbg(bp->dev, "poll: status = %08lx, budget = %d\n",
(unsigned long)status, budget);
- work_done = macb_rx(bp, budget);
+ work_done = bp->macbgem_ops.mog_rx(bp, budget);
if (work_done < budget) {
napi_complete(napi);
@@ -738,7 +868,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
* now.
*/
macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
- macb_writel(bp, ISR, MACB_BIT(RCOMP));
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ macb_writel(bp, ISR, MACB_BIT(RCOMP));
if (napi_schedule_prep(&bp->napi)) {
netdev_vdbg(bp->dev, "scheduling RX softirq\n");
@@ -868,12 +999,71 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
+static void macb_init_rx_buffer_size(struct macb *bp, size_t size)
+{
+ if (!macb_is_gem(bp)) {
+ bp->rx_buffer_size = MACB_RX_BUFFER_SIZE;
+ } else {
+ bp->rx_buffer_size = size;
+
+ if (bp->rx_buffer_size % RX_BUFFER_MULTIPLE) {
+ netdev_dbg(bp->dev,
+ "RX buffer must be multiple of %d bytes, expanding\n",
+ RX_BUFFER_MULTIPLE);
+ bp->rx_buffer_size =
+ roundup(bp->rx_buffer_size, RX_BUFFER_MULTIPLE);
+ }
+ }
+
+ netdev_dbg(bp->dev, "mtu [%u] rx_buffer_size [%Zu]\n",
+ bp->dev->mtu, bp->rx_buffer_size);
+}
+
+static void gem_free_rx_buffers(struct macb *bp)
+{
+ struct sk_buff *skb;
+ struct macb_dma_desc *desc;
+ dma_addr_t addr;
+ int i;
+
+ if (!bp->rx_skbuff)
+ return;
+
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ skb = bp->rx_skbuff[i];
+
+ if (skb == NULL)
+ continue;
+
+ desc = &bp->rx_ring[i];
+ addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
+ dma_unmap_single(&bp->pdev->dev, addr, skb->len,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ skb = NULL;
+ }
+
+ kfree(bp->rx_skbuff);
+ bp->rx_skbuff = NULL;
+}
+
+static void macb_free_rx_buffers(struct macb *bp)
+{
+ if (bp->rx_buffers) {
+ dma_free_coherent(&bp->pdev->dev,
+ RX_RING_SIZE * bp->rx_buffer_size,
+ bp->rx_buffers, bp->rx_buffers_dma);
+ bp->rx_buffers = NULL;
+ }
+}
+
static void macb_free_consistent(struct macb *bp)
{
if (bp->tx_skb) {
kfree(bp->tx_skb);
bp->tx_skb = NULL;
}
+ bp->macbgem_ops.mog_free_rx_buffers(bp);
if (bp->rx_ring) {
dma_free_coherent(&bp->pdev->dev, RX_RING_BYTES,
bp->rx_ring, bp->rx_ring_dma);
@@ -884,12 +1074,37 @@ static void macb_free_consistent(struct macb *bp)
bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL;
}
- if (bp->rx_buffers) {
- dma_free_coherent(&bp->pdev->dev,
- RX_RING_SIZE * RX_BUFFER_SIZE,
- bp->rx_buffers, bp->rx_buffers_dma);
- bp->rx_buffers = NULL;
- }
+}
+
+static int gem_alloc_rx_buffers(struct macb *bp)
+{
+ int size;
+
+ size = RX_RING_SIZE * sizeof(struct sk_buff *);
+ bp->rx_skbuff = kzalloc(size, GFP_KERNEL);
+ if (!bp->rx_skbuff)
+ return -ENOMEM;
+ else
+ netdev_dbg(bp->dev,
+ "Allocated %d RX struct sk_buff entries at %p\n",
+ RX_RING_SIZE, bp->rx_skbuff);
+ return 0;
+}
+
+static int macb_alloc_rx_buffers(struct macb *bp)
+{
+ int size;
+
+ size = RX_RING_SIZE * bp->rx_buffer_size;
+ bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size,
+ &bp->rx_buffers_dma, GFP_KERNEL);
+ if (!bp->rx_buffers)
+ return -ENOMEM;
+ else
+ netdev_dbg(bp->dev,
+ "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n",
+ size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers);
+ return 0;
}
static int macb_alloc_consistent(struct macb *bp)
@@ -919,14 +1134,8 @@ static int macb_alloc_consistent(struct macb *bp)
"Allocated TX ring of %d bytes at %08lx (mapped %p)\n",
size, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
- size = RX_RING_SIZE * RX_BUFFER_SIZE;
- bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size,
- &bp->rx_buffers_dma, GFP_KERNEL);
- if (!bp->rx_buffers)
+ if (bp->macbgem_ops.mog_alloc_rx_buffers(bp))
goto out_err;
- netdev_dbg(bp->dev,
- "Allocated RX buffers of %d bytes at %08lx (mapped %p)\n",
- size, (unsigned long)bp->rx_buffers_dma, bp->rx_buffers);
return 0;
@@ -935,6 +1144,21 @@ out_err:
return -ENOMEM;
}
+static void gem_init_rings(struct macb *bp)
+{
+ int i;
+
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ bp->tx_ring[i].addr = 0;
+ bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
+ }
+ bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
+
+ bp->rx_tail = bp->rx_prepared_head = bp->tx_head = bp->tx_tail = 0;
+
+ gem_rx_refill(bp);
+}
+
static void macb_init_rings(struct macb *bp)
{
int i;
@@ -944,7 +1168,7 @@ static void macb_init_rings(struct macb *bp)
for (i = 0; i < RX_RING_SIZE; i++) {
bp->rx_ring[i].addr = addr;
bp->rx_ring[i].ctrl = 0;
- addr += RX_BUFFER_SIZE;
+ addr += bp->rx_buffer_size;
}
bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
@@ -1054,7 +1278,7 @@ static void macb_configure_dma(struct macb *bp)
if (macb_is_gem(bp)) {
dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L);
- dmacfg |= GEM_BF(RXBS, RX_BUFFER_SIZE / 64);
+ dmacfg |= GEM_BF(RXBS, bp->rx_buffer_size / RX_BUFFER_MULTIPLE);
dmacfg |= GEM_BF(FBLDO, 16);
dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L);
dmacfg &= ~GEM_BIT(ENDIA);
@@ -1062,6 +1286,17 @@ static void macb_configure_dma(struct macb *bp)
}
}
+/*
+ * Configure peripheral capacities according to integration options used
+ */
+static void macb_configure_caps(struct macb *bp)
+{
+ if (macb_is_gem(bp)) {
+ if (GEM_BF(IRQCOR, gem_readl(bp, DCFG1)) == 0)
+ bp->caps |= MACB_CAPS_ISR_CLEAR_ON_WRITE;
+ }
+}
+
static void macb_init_hw(struct macb *bp)
{
u32 config;
@@ -1084,6 +1319,7 @@ static void macb_init_hw(struct macb *bp)
bp->duplex = DUPLEX_HALF;
macb_configure_dma(bp);
+ macb_configure_caps(bp);
/* Initialize TX and RX buffers */
macb_writel(bp, RBQP, bp->rx_ring_dma);
@@ -1219,6 +1455,7 @@ EXPORT_SYMBOL_GPL(macb_set_rx_mode);
static int macb_open(struct net_device *dev)
{
struct macb *bp = netdev_priv(dev);
+ size_t bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN;
int err;
netdev_dbg(bp->dev, "open\n");
@@ -1230,6 +1467,9 @@ static int macb_open(struct net_device *dev)
if (!bp->phy_dev)
return -EAGAIN;
+ /* RX buffers initialization */
+ macb_init_rx_buffer_size(bp, bufsz);
+
err = macb_alloc_consistent(bp);
if (err) {
netdev_err(dev, "Unable to allocate DMA memory (error %d)\n",
@@ -1239,7 +1479,7 @@ static int macb_open(struct net_device *dev)
napi_enable(&bp->napi);
- macb_init_rings(bp);
+ bp->macbgem_ops.mog_init_rings(bp);
macb_init_hw(bp);
/* schedule a link state check */
@@ -1558,6 +1798,19 @@ static int __init macb_probe(struct platform_device *pdev)
dev->base_addr = regs->start;
+ /* setup appropriated routines according to adapter type */
+ if (macb_is_gem(bp)) {
+ bp->macbgem_ops.mog_alloc_rx_buffers = gem_alloc_rx_buffers;
+ bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers;
+ bp->macbgem_ops.mog_init_rings = gem_init_rings;
+ bp->macbgem_ops.mog_rx = gem_rx;
+ } else {
+ bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers;
+ bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers;
+ bp->macbgem_ops.mog_init_rings = macb_init_rings;
+ bp->macbgem_ops.mog_rx = macb_rx;
+ }
+
/* Set MII management clock divider */
config = macb_mdc_clk_div(bp);
config |= macb_dbw(bp);
@@ -1635,7 +1888,6 @@ err_out_put_pclk:
err_out_free_dev:
free_netdev(dev);
err_out:
- platform_set_drvdata(pdev, NULL);
return err;
}
@@ -1661,7 +1913,6 @@ static int __exit macb_remove(struct platform_device *pdev)
clk_disable_unprepare(bp->pclk);
clk_put(bp->pclk);
free_netdev(dev);
- platform_set_drvdata(pdev, NULL);
}
return 0;
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 993d703..f407615 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -300,6 +300,8 @@
#define MACB_REV_SIZE 16
/* Bitfields in DCFG1. */
+#define GEM_IRQCOR_OFFSET 23
+#define GEM_IRQCOR_SIZE 1
#define GEM_DBWDEF_OFFSET 25
#define GEM_DBWDEF_SIZE 3
@@ -323,6 +325,9 @@
#define MACB_MAN_READ 2
#define MACB_MAN_CODE 2
+/* Capability mask bits */
+#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x1
+
/* Bit manipulation macros */
#define MACB_BIT(name) \
(1 << MACB_##name##_OFFSET)
@@ -540,12 +545,24 @@ struct gem_stats {
u32 rx_udp_checksum_errors;
};
+struct macb;
+
+struct macb_or_gem_ops {
+ int (*mog_alloc_rx_buffers)(struct macb *bp);
+ void (*mog_free_rx_buffers)(struct macb *bp);
+ void (*mog_init_rings)(struct macb *bp);
+ int (*mog_rx)(struct macb *bp, int budget);
+};
+
struct macb {
void __iomem *regs;
unsigned int rx_tail;
+ unsigned int rx_prepared_head;
struct macb_dma_desc *rx_ring;
+ struct sk_buff **rx_skbuff;
void *rx_buffers;
+ size_t rx_buffer_size;
unsigned int tx_head, tx_tail;
struct macb_dma_desc *tx_ring;
@@ -568,12 +585,16 @@ struct macb {
dma_addr_t tx_ring_dma;
dma_addr_t rx_buffers_dma;
+ struct macb_or_gem_ops macbgem_ops;
+
struct mii_bus *mii_bus;
struct phy_device *phy_dev;
unsigned int link;
unsigned int speed;
unsigned int duplex;
+ u32 caps;
+
phy_interface_t phy_interface;
/* AT91RM9200 transmit */
diff --git a/drivers/net/ethernet/calxeda/Kconfig b/drivers/net/ethernet/calxeda/Kconfig
index aba435c..184a063 100644
--- a/drivers/net/ethernet/calxeda/Kconfig
+++ b/drivers/net/ethernet/calxeda/Kconfig
@@ -1,6 +1,6 @@
config NET_CALXEDA_XGMAC
tristate "Calxeda 1G/10G XGMAC Ethernet driver"
- depends on HAS_IOMEM
+ depends on HAS_IOMEM && HAS_DMA
select CRC32
help
This is the driver for the XGMAC Ethernet IP block found on Calxeda
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index 4a1f2fa..7cb148c 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -1790,7 +1790,6 @@ err_io:
free_netdev(ndev);
err_alloc:
release_mem_region(res->start, resource_size(res));
- platform_set_drvdata(pdev, NULL);
return ret;
}
@@ -1813,7 +1812,6 @@ static int xgmac_remove(struct platform_device *pdev)
free_irq(ndev->irq, ndev);
free_irq(priv->pmt_irq, ndev);
- platform_set_drvdata(pdev, NULL);
unregister_netdev(ndev);
netif_napi_del(&priv->napi);
diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
index 9624cfe..d7048db 100644
--- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
+++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c
@@ -1351,22 +1351,11 @@ static void remove_one(struct pci_dev *pdev)
t1_sw_reset(pdev);
}
-static struct pci_driver driver = {
+static struct pci_driver cxgb_pci_driver = {
.name = DRV_NAME,
.id_table = t1_pci_tbl,
.probe = init_one,
.remove = remove_one,
};
-static int __init t1_init_module(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit t1_cleanup_module(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(t1_init_module);
-module_exit(t1_cleanup_module);
+module_pci_driver(cxgb_pci_driver);
diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
index 0c96e5f..4058b85 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c
@@ -1246,6 +1246,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
struct tid_range stid_range, tid_range;
struct mtutab mtutab;
unsigned int l2t_capacity;
+ struct l2t_data *l2td;
t = kzalloc(sizeof(*t), GFP_KERNEL);
if (!t)
@@ -1261,8 +1262,8 @@ int cxgb3_offload_activate(struct adapter *adapter)
goto out_free;
err = -ENOMEM;
- RCU_INIT_POINTER(dev->l2opt, t3_init_l2t(l2t_capacity));
- if (!L2DATA(dev))
+ l2td = t3_init_l2t(l2t_capacity);
+ if (!l2td)
goto out_free;
natids = min(tid_range.num / 2, MAX_ATIDS);
@@ -1279,6 +1280,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
INIT_LIST_HEAD(&t->list_node);
t->dev = dev;
+ RCU_INIT_POINTER(dev->l2opt, l2td);
T3C_DATA(dev) = t;
dev->recv = process_rx;
dev->neigh_update = t3_l2t_update;
@@ -1294,8 +1296,7 @@ int cxgb3_offload_activate(struct adapter *adapter)
return 0;
out_free_l2t:
- t3_free_l2t(L2DATA(dev));
- RCU_INIT_POINTER(dev->l2opt, NULL);
+ t3_free_l2t(l2td);
out_free:
kfree(t);
return err;
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index f12e6b8..687ec4a 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -455,6 +455,11 @@ static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q,
q->pg_chunk.offset = 0;
mapping = pci_map_page(adapter->pdev, q->pg_chunk.page,
0, q->alloc_size, PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(adapter->pdev, mapping))) {
+ __free_pages(q->pg_chunk.page, order);
+ q->pg_chunk.page = NULL;
+ return -EIO;
+ }
q->pg_chunk.mapping = mapping;
}
sd->pg_chunk = q->pg_chunk;
@@ -949,40 +954,75 @@ static inline unsigned int calc_tx_descs(const struct sk_buff *skb)
return flits_to_desc(flits);
}
+
+/* map_skb - map a packet main body and its page fragments
+ * @pdev: the PCI device
+ * @skb: the packet
+ * @addr: placeholder to save the mapped addresses
+ *
+ * map the main body of an sk_buff and its page fragments, if any.
+ */
+static int map_skb(struct pci_dev *pdev, const struct sk_buff *skb,
+ dma_addr_t *addr)
+{
+ const skb_frag_t *fp, *end;
+ const struct skb_shared_info *si;
+
+ *addr = pci_map_single(pdev, skb->data, skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, *addr))
+ goto out_err;
+
+ si = skb_shinfo(skb);
+ end = &si->frags[si->nr_frags];
+
+ for (fp = si->frags; fp < end; fp++) {
+ *++addr = skb_frag_dma_map(&pdev->dev, fp, 0, skb_frag_size(fp),
+ DMA_TO_DEVICE);
+ if (pci_dma_mapping_error(pdev, *addr))
+ goto unwind;
+ }
+ return 0;
+
+unwind:
+ while (fp-- > si->frags)
+ dma_unmap_page(&pdev->dev, *--addr, skb_frag_size(fp),
+ DMA_TO_DEVICE);
+
+ pci_unmap_single(pdev, addr[-1], skb_headlen(skb), PCI_DMA_TODEVICE);
+out_err:
+ return -ENOMEM;
+}
+
/**
- * make_sgl - populate a scatter/gather list for a packet
+ * write_sgl - populate a scatter/gather list for a packet
* @skb: the packet
* @sgp: the SGL to populate
* @start: start address of skb main body data to include in the SGL
* @len: length of skb main body data to include in the SGL
- * @pdev: the PCI device
+ * @addr: the list of the mapped addresses
*
- * Generates a scatter/gather list for the buffers that make up a packet
+ * Copies the scatter/gather list for the buffers that make up a packet
* and returns the SGL size in 8-byte words. The caller must size the SGL
* appropriately.
*/
-static inline unsigned int make_sgl(const struct sk_buff *skb,
+static inline unsigned int write_sgl(const struct sk_buff *skb,
struct sg_ent *sgp, unsigned char *start,
- unsigned int len, struct pci_dev *pdev)
+ unsigned int len, const dma_addr_t *addr)
{
- dma_addr_t mapping;
- unsigned int i, j = 0, nfrags;
+ unsigned int i, j = 0, k = 0, nfrags;
if (len) {
- mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
sgp->len[0] = cpu_to_be32(len);
- sgp->addr[0] = cpu_to_be64(mapping);
- j = 1;
+ sgp->addr[j++] = cpu_to_be64(addr[k++]);
}
nfrags = skb_shinfo(skb)->nr_frags;
for (i = 0; i < nfrags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- mapping = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
- DMA_TO_DEVICE);
sgp->len[j] = cpu_to_be32(skb_frag_size(frag));
- sgp->addr[j] = cpu_to_be64(mapping);
+ sgp->addr[j] = cpu_to_be64(addr[k++]);
j ^= 1;
if (j == 0)
++sgp;
@@ -1138,7 +1178,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
const struct port_info *pi,
unsigned int pidx, unsigned int gen,
struct sge_txq *q, unsigned int ndesc,
- unsigned int compl)
+ unsigned int compl, const dma_addr_t *addr)
{
unsigned int flits, sgl_flits, cntrl, tso_info;
struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
@@ -1196,7 +1236,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
}
sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
- sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
+ sgl_flits = write_sgl(skb, sgp, skb->data, skb_headlen(skb), addr);
write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
@@ -1227,6 +1267,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
struct netdev_queue *txq;
struct sge_qset *qs;
struct sge_txq *q;
+ dma_addr_t addr[MAX_SKB_FRAGS + 1];
/*
* The chip min packet length is 9 octets but play safe and reject
@@ -1255,6 +1296,11 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
+ if (unlikely(map_skb(adap->pdev, skb, addr) < 0)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
q->in_use += ndesc;
if (unlikely(credits - ndesc < q->stop_thres)) {
t3_stop_tx_queue(txq, qs, q);
@@ -1312,7 +1358,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
if (likely(!skb_shared(skb)))
skb_orphan(skb);
- write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
+ write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl, addr);
check_ring_tx_db(adap, q);
return NETDEV_TX_OK;
}
@@ -1537,10 +1583,9 @@ static void deferred_unmap_destructor(struct sk_buff *skb)
dui = (struct deferred_unmap_info *)skb->head;
p = dui->addr;
- if (skb->tail - skb->transport_header)
- pci_unmap_single(dui->pdev, *p++,
- skb->tail - skb->transport_header,
- PCI_DMA_TODEVICE);
+ if (skb_tail_pointer(skb) - skb_transport_header(skb))
+ pci_unmap_single(dui->pdev, *p++, skb_tail_pointer(skb) -
+ skb_transport_header(skb), PCI_DMA_TODEVICE);
si = skb_shinfo(skb);
for (i = 0; i < si->nr_frags; i++)
@@ -1578,7 +1623,8 @@ static void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev,
*/
static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
struct sge_txq *q, unsigned int pidx,
- unsigned int gen, unsigned int ndesc)
+ unsigned int gen, unsigned int ndesc,
+ const dma_addr_t *addr)
{
unsigned int sgl_flits, flits;
struct work_request_hdr *from;
@@ -1599,9 +1645,9 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
flits = skb_transport_offset(skb) / 8;
sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
- sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb),
- skb->tail - skb->transport_header,
- adap->pdev);
+ sgl_flits = write_sgl(skb, sgp, skb_transport_header(skb),
+ skb_tail_pointer(skb) -
+ skb_transport_header(skb), addr);
if (need_skb_unmap()) {
setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits);
skb->destructor = deferred_unmap_destructor;
@@ -1627,7 +1673,7 @@ static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
flits = skb_transport_offset(skb) / 8; /* headers */
cnt = skb_shinfo(skb)->nr_frags;
- if (skb->tail != skb->transport_header)
+ if (skb_tail_pointer(skb) != skb_transport_header(skb))
cnt++;
return flits_to_desc(flits + sgl_len(cnt));
}
@@ -1659,6 +1705,11 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
goto again;
}
+ if (map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) {
+ spin_unlock(&q->lock);
+ return NET_XMIT_SUCCESS;
+ }
+
gen = q->gen;
q->in_use += ndesc;
pidx = q->pidx;
@@ -1669,7 +1720,7 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
}
spin_unlock(&q->lock);
- write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc, (dma_addr_t *)skb->head);
check_ring_tx_db(adap, q);
return NET_XMIT_SUCCESS;
}
@@ -1687,6 +1738,7 @@ static void restart_offloadq(unsigned long data)
struct sge_txq *q = &qs->txq[TXQ_OFLD];
const struct port_info *pi = netdev_priv(qs->netdev);
struct adapter *adap = pi->adapter;
+ unsigned int written = 0;
spin_lock(&q->lock);
again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
@@ -1706,10 +1758,14 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
break;
}
+ if (map_skb(adap->pdev, skb, (dma_addr_t *)skb->head))
+ break;
+
gen = q->gen;
q->in_use += ndesc;
pidx = q->pidx;
q->pidx += ndesc;
+ written += ndesc;
if (q->pidx >= q->size) {
q->pidx -= q->size;
q->gen ^= 1;
@@ -1717,7 +1773,8 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
__skb_unlink(skb, &q->sendq);
spin_unlock(&q->lock);
- write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+ write_ofld_wr(adap, skb, q, pidx, gen, ndesc,
+ (dma_addr_t *)skb->head);
spin_lock(&q->lock);
}
spin_unlock(&q->lock);
@@ -1727,8 +1784,9 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
set_bit(TXQ_LAST_PKT_DB, &q->flags);
#endif
wmb();
- t3_write_reg(adap, A_SG_KDOORBELL,
- F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+ if (likely(written))
+ t3_write_reg(adap, A_SG_KDOORBELL,
+ F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
}
/**
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 681804b..2aafb80 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -51,7 +51,7 @@
#include "t4_hw.h"
#define FW_VERSION_MAJOR 1
-#define FW_VERSION_MINOR 1
+#define FW_VERSION_MINOR 4
#define FW_VERSION_MICRO 0
#define FW_VERSION_MAJOR_T5 0
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 3cd397d..5a3256b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -4842,8 +4842,17 @@ static int adap_init0(struct adapter *adap)
* is excessively mismatched relative to the driver.)
*/
ret = t4_check_fw_version(adap);
+
+ /* The error code -EFAULT is returned by t4_check_fw_version() if
+ * firmware on adapter < supported firmware. If firmware on adapter
+ * is too old (not supported by driver) and we're the MASTER_PF set
+ * adapter state to DEV_STATE_UNINIT to force firmware upgrade
+ * and reinitialization.
+ */
+ if ((adap->flags & MASTER_PF) && ret == -EFAULT)
+ state = DEV_STATE_UNINIT;
if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) {
- if (ret == -EINVAL || ret > 0) {
+ if (ret == -EINVAL || ret == -EFAULT || ret > 0) {
if (upgrade_fw(adap) >= 0) {
/*
* Note that the chip was reset as part of the
@@ -4852,7 +4861,21 @@ static int adap_init0(struct adapter *adap)
*/
reset = 0;
ret = t4_check_fw_version(adap);
- }
+ } else
+ if (ret == -EFAULT) {
+ /*
+ * Firmware is old but still might
+ * work if we force reinitialization
+ * of the adapter. Ignoring FW upgrade
+ * failure.
+ */
+ dev_warn(adap->pdev_dev,
+ "Ignoring firmware upgrade "
+ "failure, and forcing driver "
+ "to reinitialize the "
+ "adapter.\n");
+ ret = 0;
+ }
}
if (ret < 0)
return ret;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index 2bfbb20..ac311f5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -1294,7 +1294,7 @@ static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb)
flits = skb_transport_offset(skb) / 8U; /* headers */
cnt = skb_shinfo(skb)->nr_frags;
- if (skb->tail != skb->transport_header)
+ if (skb_tail_pointer(skb) != skb_transport_header(skb))
cnt++;
return flits + sgl_len(cnt);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index d02d4e8..4cbb2f9 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -938,6 +938,15 @@ int t4_check_fw_version(struct adapter *adapter)
memcpy(adapter->params.api_vers, api_vers,
sizeof(adapter->params.api_vers));
+ if (major < exp_major || (major == exp_major && minor < exp_minor) ||
+ (major == exp_major && minor == exp_minor && micro < exp_micro)) {
+ dev_err(adapter->pdev_dev,
+ "Card has firmware version %u.%u.%u, minimum "
+ "supported firmware is %u.%u.%u.\n", major, minor,
+ micro, exp_major, exp_minor, exp_micro);
+ return -EFAULT;
+ }
+
if (major != exp_major) { /* major mismatch - fail */
dev_err(adapter->pdev_dev,
"card FW has major version %u, driver wants %u\n",
@@ -3773,7 +3782,6 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
p->lport = j;
p->rss_size = rss_size;
memcpy(adap->port[i]->dev_addr, addr, ETH_ALEN);
- adap->port[i]->dev_id = j;
ret = ntohl(c.u.info.lstatus_to_modtype);
p->mdio_addr = (ret & FW_PORT_CMD_MDIOCAP) ?
diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
index 8388e36..7403dff 100644
--- a/drivers/net/ethernet/cirrus/Kconfig
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -44,7 +44,6 @@ config CS89x0_PLATFORM
config EP93XX_ETH
tristate "EP93xx Ethernet support"
depends on ARM && ARCH_EP93XX
- select NET_CORE
select MII
help
This is a driver for the ethernet hardware included in EP93xx CPUs.
diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c
index 67b0388..e3d4ec8 100644
--- a/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@ -783,7 +783,6 @@ static int ep93xx_eth_remove(struct platform_device *pdev)
dev = platform_get_drvdata(pdev);
if (dev == NULL)
return 0;
- platform_set_drvdata(pdev, NULL);
ep = netdev_priv(dev);
diff --git a/drivers/net/ethernet/davicom/Kconfig b/drivers/net/ethernet/davicom/Kconfig
index 9745fe5..316c5e5 100644
--- a/drivers/net/ethernet/davicom/Kconfig
+++ b/drivers/net/ethernet/davicom/Kconfig
@@ -6,7 +6,6 @@ config DM9000
tristate "DM9000 support"
depends on ARM || BLACKFIN || MIPS || COLDFIRE
select CRC32
- select NET_CORE
select MII
---help---
Support for DM9000 chipset.
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index 9105465..a13b312 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -29,6 +29,8 @@
#include <linux/spinlock.h>
#include <linux/crc32.h>
#include <linux/mii.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
#include <linux/ethtool.h>
#include <linux/dm9000.h>
#include <linux/delay.h>
@@ -827,7 +829,7 @@ dm9000_hash_table_unlocked(struct net_device *dev)
struct netdev_hw_addr *ha;
int i, oft;
u32 hash_val;
- u16 hash_table[4];
+ u16 hash_table[4] = { 0, 0, 0, 0x8000 }; /* broadcast address */
u8 rcr = RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN;
dm9000_dbg(db, 1, "entering %s\n", __func__);
@@ -835,13 +837,6 @@ dm9000_hash_table_unlocked(struct net_device *dev)
for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++)
iow(db, oft, dev->dev_addr[i]);
- /* Clear Hash Table */
- for (i = 0; i < 4; i++)
- hash_table[i] = 0x0;
-
- /* broadcast address */
- hash_table[3] = 0x8000;
-
if (dev->flags & IFF_PROMISC)
rcr |= RCR_PRMSC;
@@ -1358,6 +1353,31 @@ static const struct net_device_ops dm9000_netdev_ops = {
#endif
};
+static struct dm9000_plat_data *dm9000_parse_dt(struct device *dev)
+{
+ struct dm9000_plat_data *pdata;
+ struct device_node *np = dev->of_node;
+ const void *mac_addr;
+
+ if (!IS_ENABLED(CONFIG_OF) || !np)
+ return NULL;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ if (of_find_property(np, "davicom,ext-phy", NULL))
+ pdata->flags |= DM9000_PLATF_EXT_PHY;
+ if (of_find_property(np, "davicom,no-eeprom", NULL))
+ pdata->flags |= DM9000_PLATF_NO_EEPROM;
+
+ mac_addr = of_get_mac_address(np);
+ if (mac_addr)
+ memcpy(pdata->dev_addr, mac_addr, sizeof(pdata->dev_addr));
+
+ return pdata;
+}
+
/*
* Search DM9000 board, allocate space and register it
*/
@@ -1373,6 +1393,12 @@ dm9000_probe(struct platform_device *pdev)
int i;
u32 id_val;
+ if (!pdata) {
+ pdata = dm9000_parse_dt(&pdev->dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ }
+
/* Init network device */
ndev = alloc_etherdev(sizeof(struct board_info));
if (!ndev)
@@ -1673,8 +1699,6 @@ dm9000_drv_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
unregister_netdev(ndev);
dm9000_release_board(pdev, netdev_priv(ndev));
free_netdev(ndev); /* free device structure */
@@ -1683,11 +1707,20 @@ dm9000_drv_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id dm9000_of_matches[] = {
+ { .compatible = "davicom,dm9000", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, dm9000_of_matches);
+#endif
+
static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
.pm = &dm9000_drv_pm_ops,
+ .of_match_table = of_match_ptr(dm9000_of_matches),
},
.probe = dm9000_probe,
.remove = dm9000_drv_remove,
diff --git a/drivers/net/ethernet/dec/tulip/Kconfig b/drivers/net/ethernet/dec/tulip/Kconfig
index 1df33c7..eb9ba6e 100644
--- a/drivers/net/ethernet/dec/tulip/Kconfig
+++ b/drivers/net/ethernet/dec/tulip/Kconfig
@@ -126,7 +126,6 @@ config WINBOND_840
tristate "Winbond W89c840 Ethernet support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This driver is for the Winbond W89c840 chip. It also works with
diff --git a/drivers/net/ethernet/dec/tulip/interrupt.c b/drivers/net/ethernet/dec/tulip/interrupt.c
index 28a5e42..92306b3 100644
--- a/drivers/net/ethernet/dec/tulip/interrupt.c
+++ b/drivers/net/ethernet/dec/tulip/interrupt.c
@@ -76,6 +76,12 @@ int tulip_refill_rx(struct net_device *dev)
mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&tp->pdev->dev, mapping)) {
+ dev_kfree_skb(skb);
+ tp->rx_buffers[entry].skb = NULL;
+ break;
+ }
+
tp->rx_buffers[entry].mapping = mapping;
tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping);
diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c
index 1e9443d..c94152f 100644
--- a/drivers/net/ethernet/dec/tulip/tulip_core.c
+++ b/drivers/net/ethernet/dec/tulip/tulip_core.c
@@ -1410,12 +1410,6 @@ static int tulip_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return i;
}
- /* The chip will fail to enter a low-power state later unless
- * first explicitly commanded into D0 */
- if (pci_set_power_state(pdev, PCI_D0)) {
- pr_notice("Failed to set power state to D0\n");
- }
-
irq = pdev->irq;
/* alloc_etherdev ensures aligned and zeroed private structures */
diff --git a/drivers/net/ethernet/dec/tulip/xircom_cb.c b/drivers/net/ethernet/dec/tulip/xircom_cb.c
index cdbcd16..9b84cb0 100644
--- a/drivers/net/ethernet/dec/tulip/xircom_cb.c
+++ b/drivers/net/ethernet/dec/tulip/xircom_cb.c
@@ -1171,16 +1171,4 @@ investigate_write_descriptor(struct net_device *dev,
}
}
-static int __init xircom_init(void)
-{
- return pci_register_driver(&xircom_ops);
-}
-
-static void __exit xircom_exit(void)
-{
- pci_unregister_driver(&xircom_ops);
-}
-
-module_init(xircom_init)
-module_exit(xircom_exit)
-
+module_pci_driver(xircom_ops);
diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig
index ee26ce7..c543ac1 100644
--- a/drivers/net/ethernet/dlink/Kconfig
+++ b/drivers/net/ethernet/dlink/Kconfig
@@ -36,7 +36,6 @@ config SUNDANCE
tristate "Sundance Alta support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This driver is for the Sundance "Alta" chip.
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index f544b29..c827b1b 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -262,6 +262,7 @@ struct be_rx_compl_info {
u8 ipv6;
u8 vtm;
u8 pkt_type;
+ u8 ip_frag;
};
struct be_rx_obj {
@@ -332,6 +333,9 @@ enum vf_state {
#define BE_VF_UC_PMAC_COUNT 2
#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11)
+/* Ethtool set_dump flags */
+#define LANCER_INITIATE_FW_DUMP 0x1
+
struct phy_info {
u8 transceiver;
u8 autoneg;
@@ -397,6 +401,7 @@ struct be_adapter {
u32 cmd_privileges;
/* Ethtool knobs and info */
char fw_ver[FW_VER_LEN];
+ char fw_on_flash[FW_VER_LEN];
int if_handle; /* Used to configure filtering */
u32 *pmac_id; /* MAC addr handle used by BE card */
u32 beacon_state; /* for set_phys_id */
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index fd7b547..6e6e0a1 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -562,7 +562,7 @@ int lancer_test_and_set_rdy_state(struct be_adapter *adapter)
resource_error = lancer_provisioning_error(adapter);
if (resource_error)
- return -1;
+ return -EAGAIN;
status = lancer_wait_ready(adapter);
if (!status) {
@@ -590,8 +590,8 @@ int lancer_test_and_set_rdy_state(struct be_adapter *adapter)
* when PF provisions resources.
*/
resource_error = lancer_provisioning_error(adapter);
- if (status == -1 && !resource_error)
- adapter->eeh_error = true;
+ if (resource_error)
+ status = -EAGAIN;
return status;
}
@@ -2976,22 +2976,17 @@ static struct be_nic_resource_desc *be_get_nic_desc(u8 *buf, u32 desc_count,
for (i = 0; i < desc_count; i++) {
desc->desc_len = desc->desc_len ? : RESOURCE_DESC_SIZE;
if (((void *)desc + desc->desc_len) >
- (void *)(buf + max_buf_size)) {
- desc = NULL;
- break;
- }
+ (void *)(buf + max_buf_size))
+ return NULL;
if (desc->desc_type == NIC_RESOURCE_DESC_TYPE_V0 ||
desc->desc_type == NIC_RESOURCE_DESC_TYPE_V1)
- break;
+ return desc;
desc = (void *)desc + desc->desc_len;
}
- if (!desc || i == MAX_RESOURCE_DESC)
- return NULL;
-
- return desc;
+ return NULL;
}
/* Uses Mbox */
@@ -3260,6 +3255,72 @@ err:
return status;
}
+static int lancer_wait_idle(struct be_adapter *adapter)
+{
+#define SLIPORT_IDLE_TIMEOUT 30
+ u32 reg_val;
+ int status = 0, i;
+
+ for (i = 0; i < SLIPORT_IDLE_TIMEOUT; i++) {
+ reg_val = ioread32(adapter->db + PHYSDEV_CONTROL_OFFSET);
+ if ((reg_val & PHYSDEV_CONTROL_INP_MASK) == 0)
+ break;
+
+ ssleep(1);
+ }
+
+ if (i == SLIPORT_IDLE_TIMEOUT)
+ status = -1;
+
+ return status;
+}
+
+int lancer_physdev_ctrl(struct be_adapter *adapter, u32 mask)
+{
+ int status = 0;
+
+ status = lancer_wait_idle(adapter);
+ if (status)
+ return status;
+
+ iowrite32(mask, adapter->db + PHYSDEV_CONTROL_OFFSET);
+
+ return status;
+}
+
+/* Routine to check whether dump image is present or not */
+bool dump_present(struct be_adapter *adapter)
+{
+ u32 sliport_status = 0;
+
+ sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
+ return !!(sliport_status & SLIPORT_STATUS_DIP_MASK);
+}
+
+int lancer_initiate_dump(struct be_adapter *adapter)
+{
+ int status;
+
+ /* give firmware reset and diagnostic dump */
+ status = lancer_physdev_ctrl(adapter, PHYSDEV_CONTROL_FW_RESET_MASK |
+ PHYSDEV_CONTROL_DD_MASK);
+ if (status < 0) {
+ dev_err(&adapter->pdev->dev, "Firmware reset failed\n");
+ return status;
+ }
+
+ status = lancer_wait_idle(adapter);
+ if (status)
+ return status;
+
+ if (!dump_present(adapter)) {
+ dev_err(&adapter->pdev->dev, "Dump image not present\n");
+ return -1;
+ }
+
+ return 0;
+}
+
/* Uses sync mcc */
int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain)
{
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index 025bdb0..5228d88 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -1937,6 +1937,9 @@ extern int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter,
struct be_dma_mem *cmd,
struct be_fat_conf_params *cfgs);
extern int lancer_wait_ready(struct be_adapter *adapter);
+extern int lancer_physdev_ctrl(struct be_adapter *adapter, u32 mask);
+extern int lancer_initiate_dump(struct be_adapter *adapter);
+extern bool dump_present(struct be_adapter *adapter);
extern int lancer_test_and_set_rdy_state(struct be_adapter *adapter);
extern int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name);
extern int be_cmd_get_func_config(struct be_adapter *adapter);
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 3d4461a..4f8c941 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -177,19 +177,15 @@ static void be_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct be_adapter *adapter = netdev_priv(netdev);
- char fw_on_flash[FW_VER_LEN];
-
- memset(fw_on_flash, 0 , sizeof(fw_on_flash));
- be_cmd_get_fw_ver(adapter, adapter->fw_ver, fw_on_flash);
strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version));
- if (!memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN))
+ if (!memcmp(adapter->fw_ver, adapter->fw_on_flash, FW_VER_LEN))
strlcpy(drvinfo->fw_version, adapter->fw_ver,
sizeof(drvinfo->fw_version));
else
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%s [%s]", adapter->fw_ver, fw_on_flash);
+ "%s [%s]", adapter->fw_ver, adapter->fw_on_flash);
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
sizeof(drvinfo->bus_info));
@@ -673,6 +669,34 @@ be_set_phys_id(struct net_device *netdev,
return 0;
}
+static int be_set_dump(struct net_device *netdev, struct ethtool_dump *dump)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct device *dev = &adapter->pdev->dev;
+ int status;
+
+ if (!lancer_chip(adapter)) {
+ dev_err(dev, "FW dump not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (dump_present(adapter)) {
+ dev_err(dev, "Previous dump not cleared, not forcing dump\n");
+ return 0;
+ }
+
+ switch (dump->flag) {
+ case LANCER_INITIATE_FW_DUMP:
+ status = lancer_initiate_dump(adapter);
+ if (!status)
+ dev_info(dev, "F/w dump initiated successfully\n");
+ break;
+ default:
+ dev_err(dev, "Invalid dump level: 0x%x\n", dump->flag);
+ return -EINVAL;
+ }
+ return status;
+}
static void
be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
@@ -1110,6 +1134,7 @@ const struct ethtool_ops be_ethtool_ops = {
.set_pauseparam = be_set_pauseparam,
.get_strings = be_get_stat_strings,
.set_phys_id = be_set_phys_id,
+ .set_dump = be_set_dump,
.get_msglevel = be_get_msg_level,
.set_msglevel = be_set_msg_level,
.get_sset_count = be_get_sset_count,
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index 3c1099b..3e21621 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -53,10 +53,12 @@
#define PHYSDEV_CONTROL_OFFSET 0x414
#define SLIPORT_STATUS_ERR_MASK 0x80000000
+#define SLIPORT_STATUS_DIP_MASK 0x02000000
#define SLIPORT_STATUS_RN_MASK 0x01000000
#define SLIPORT_STATUS_RDY_MASK 0x00800000
#define SLI_PORT_CONTROL_IP_MASK 0x08000000
#define PHYSDEV_CONTROL_FW_RESET_MASK 0x00000002
+#define PHYSDEV_CONTROL_DD_MASK 0x00000004
#define PHYSDEV_CONTROL_INP_MASK 0x40000000
#define SLIPORT_ERROR_NO_RESOURCE1 0x2
@@ -356,7 +358,7 @@ struct amap_eth_rx_compl_v0 {
u8 ip_version; /* dword 1 */
u8 macdst[6]; /* dword 1 */
u8 vtp; /* dword 1 */
- u8 rsvd0; /* dword 1 */
+ u8 ip_frag; /* dword 1 */
u8 fragndx[10]; /* dword 1 */
u8 ct[2]; /* dword 1 */
u8 sw; /* dword 1 */
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index a444110..cd69ac7 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -780,26 +780,18 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
if (unlikely(!skb))
return skb;
- if (vlan_tx_tag_present(skb)) {
+ if (vlan_tx_tag_present(skb))
vlan_tag = be_get_tx_vlan_tag(adapter, skb);
- skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
- if (skb)
- skb->vlan_tci = 0;
- }
-
- if (qnq_async_evt_rcvd(adapter) && adapter->pvid) {
- if (!vlan_tag)
- vlan_tag = adapter->pvid;
- if (skip_hw_vlan)
- *skip_hw_vlan = true;
- }
+ else if (qnq_async_evt_rcvd(adapter) && adapter->pvid)
+ vlan_tag = adapter->pvid;
if (vlan_tag) {
skb = __vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
if (unlikely(!skb))
return skb;
-
skb->vlan_tci = 0;
+ if (skip_hw_vlan)
+ *skip_hw_vlan = true;
}
/* Insert the outer VLAN, if any */
@@ -842,32 +834,39 @@ static int be_vlan_tag_tx_chk(struct be_adapter *adapter, struct sk_buff *skb)
return vlan_tx_tag_present(skb) || adapter->pvid || adapter->qnq_vid;
}
-static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb)
+static int be_ipv6_tx_stall_chk(struct be_adapter *adapter,
+ struct sk_buff *skb)
{
- return BE3_chip(adapter) &&
- be_ipv6_exthdr_check(skb);
+ return BE3_chip(adapter) && be_ipv6_exthdr_check(skb);
}
-static netdev_tx_t be_xmit(struct sk_buff *skb,
- struct net_device *netdev)
+static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
+ struct sk_buff *skb,
+ bool *skip_hw_vlan)
{
- struct be_adapter *adapter = netdev_priv(netdev);
- struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];
- struct be_queue_info *txq = &txo->q;
- struct iphdr *ip = NULL;
- u32 wrb_cnt = 0, copied = 0;
- u32 start = txq->head, eth_hdr_len;
- bool dummy_wrb, stopped = false;
- bool skip_hw_vlan = false;
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
+ unsigned int eth_hdr_len;
+ struct iphdr *ip;
- eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
- VLAN_ETH_HLEN : ETH_HLEN;
+ /* Lancer ASIC has a bug wherein packets that are 32 bytes or less
+ * may cause a transmit stall on that port. So the work-around is to
+ * pad such packets to a 36-byte length.
+ */
+ if (unlikely(lancer_chip(adapter) && skb->len <= 32)) {
+ if (skb_padto(skb, 36))
+ goto tx_drop;
+ skb->len = 36;
+ }
/* For padded packets, BE HW modifies tot_len field in IP header
* incorrecly when VLAN tag is inserted by HW.
+ * For padded packets, Lancer computes incorrect checksum.
*/
- if (skb->len <= 60 && vlan_tx_tag_present(skb) && is_ipv4_pkt(skb)) {
+ eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
+ VLAN_ETH_HLEN : ETH_HLEN;
+ if (skb->len <= 60 &&
+ (lancer_chip(adapter) || vlan_tx_tag_present(skb)) &&
+ is_ipv4_pkt(skb)) {
ip = (struct iphdr *)ip_hdr(skb);
pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
}
@@ -877,15 +876,15 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
*/
if ((adapter->function_mode & UMC_ENABLED) &&
veh->h_vlan_proto == htons(ETH_P_8021Q))
- skip_hw_vlan = true;
+ *skip_hw_vlan = true;
/* HW has a bug wherein it will calculate CSUM for VLAN
* pkts even though it is disabled.
* Manually insert VLAN in pkt.
*/
if (skb->ip_summed != CHECKSUM_PARTIAL &&
- vlan_tx_tag_present(skb)) {
- skb = be_insert_vlan_in_pkt(adapter, skb, &skip_hw_vlan);
+ vlan_tx_tag_present(skb)) {
+ skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
if (unlikely(!skb))
goto tx_drop;
}
@@ -895,8 +894,8 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
* skip HW tagging is not enabled by FW.
*/
if (unlikely(be_ipv6_tx_stall_chk(adapter, skb) &&
- (adapter->pvid || adapter->qnq_vid) &&
- !qnq_async_evt_rcvd(adapter)))
+ (adapter->pvid || adapter->qnq_vid) &&
+ !qnq_async_evt_rcvd(adapter)))
goto tx_drop;
/* Manual VLAN tag insertion to prevent:
@@ -907,11 +906,31 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
*/
if (be_ipv6_tx_stall_chk(adapter, skb) &&
be_vlan_tag_tx_chk(adapter, skb)) {
- skb = be_insert_vlan_in_pkt(adapter, skb, &skip_hw_vlan);
+ skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
if (unlikely(!skb))
goto tx_drop;
}
+ return skb;
+tx_drop:
+ dev_kfree_skb_any(skb);
+ return NULL;
+}
+
+static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];
+ struct be_queue_info *txq = &txo->q;
+ bool dummy_wrb, stopped = false;
+ u32 wrb_cnt = 0, copied = 0;
+ bool skip_hw_vlan = false;
+ u32 start = txq->head;
+
+ skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan);
+ if (!skb)
+ return NETDEV_TX_OK;
+
wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb,
@@ -941,7 +960,6 @@ static netdev_tx_t be_xmit(struct sk_buff *skb,
txq->head = start;
dev_kfree_skb_any(skb);
}
-tx_drop:
return NETDEV_TX_OK;
}
@@ -1244,30 +1262,6 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
return status;
}
-static int be_find_vfs(struct be_adapter *adapter, int vf_state)
-{
- struct pci_dev *dev, *pdev = adapter->pdev;
- int vfs = 0, assigned_vfs = 0, pos;
- u16 offset, stride;
-
- pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
- if (!pos)
- return 0;
- pci_read_config_word(pdev, pos + PCI_SRIOV_VF_OFFSET, &offset);
- pci_read_config_word(pdev, pos + PCI_SRIOV_VF_STRIDE, &stride);
-
- dev = pci_get_device(pdev->vendor, PCI_ANY_ID, NULL);
- while (dev) {
- if (dev->is_virtfn && pci_physfn(dev) == pdev) {
- vfs++;
- if (dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
- assigned_vfs++;
- }
- dev = pci_get_device(pdev->vendor, PCI_ANY_ID, dev);
- }
- return (vf_state == ASSIGNED) ? assigned_vfs : vfs;
-}
-
static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo)
{
struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]);
@@ -1607,6 +1601,8 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
compl);
}
rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, port, compl);
+ rxcp->ip_frag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0,
+ ip_frag, compl);
}
static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
@@ -1628,6 +1624,9 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
else
be_parse_rx_compl_v0(compl, rxcp);
+ if (rxcp->ip_frag)
+ rxcp->l4_csum = 0;
+
if (rxcp->vlanf) {
/* vlanf could be wrongly set in some cards.
* ignore if vtm is not set */
@@ -2176,7 +2175,7 @@ static irqreturn_t be_msix(int irq, void *dev)
static inline bool do_gro(struct be_rx_compl_info *rxcp)
{
- return (rxcp->tcpf && !rxcp->err) ? true : false;
+ return (rxcp->tcpf && !rxcp->err && rxcp->l4_csum) ? true : false;
}
static int be_process_rx(struct be_rx_obj *rxo, struct napi_struct *napi,
@@ -2774,7 +2773,7 @@ static void be_vf_clear(struct be_adapter *adapter)
struct be_vf_cfg *vf_cfg;
u32 vf;
- if (be_find_vfs(adapter, ASSIGNED)) {
+ if (pci_vfs_assigned(adapter->pdev)) {
dev_warn(&adapter->pdev->dev,
"VFs are assigned to VMs: not disabling VFs\n");
goto done;
@@ -2876,7 +2875,7 @@ static int be_vf_setup(struct be_adapter *adapter)
int status, old_vfs, vf;
struct device *dev = &adapter->pdev->dev;
- old_vfs = be_find_vfs(adapter, ENABLED);
+ old_vfs = pci_num_vf(adapter->pdev);
if (old_vfs) {
dev_info(dev, "%d VFs are already enabled\n", old_vfs);
if (old_vfs != num_vfs)
@@ -3187,7 +3186,7 @@ static int be_setup(struct be_adapter *adapter)
if (status)
goto err;
- be_cmd_get_fw_ver(adapter, adapter->fw_ver, NULL);
+ be_cmd_get_fw_ver(adapter, adapter->fw_ver, adapter->fw_on_flash);
if (adapter->vlans_added)
be_vid_config(adapter);
@@ -3533,40 +3532,6 @@ static int be_flash_skyhawk(struct be_adapter *adapter,
return 0;
}
-static int lancer_wait_idle(struct be_adapter *adapter)
-{
-#define SLIPORT_IDLE_TIMEOUT 30
- u32 reg_val;
- int status = 0, i;
-
- for (i = 0; i < SLIPORT_IDLE_TIMEOUT; i++) {
- reg_val = ioread32(adapter->db + PHYSDEV_CONTROL_OFFSET);
- if ((reg_val & PHYSDEV_CONTROL_INP_MASK) == 0)
- break;
-
- ssleep(1);
- }
-
- if (i == SLIPORT_IDLE_TIMEOUT)
- status = -1;
-
- return status;
-}
-
-static int lancer_fw_reset(struct be_adapter *adapter)
-{
- int status = 0;
-
- status = lancer_wait_idle(adapter);
- if (status)
- return status;
-
- iowrite32(PHYSDEV_CONTROL_FW_RESET_MASK, adapter->db +
- PHYSDEV_CONTROL_OFFSET);
-
- return status;
-}
-
static int lancer_fw_download(struct be_adapter *adapter,
const struct firmware *fw)
{
@@ -3644,7 +3609,8 @@ static int lancer_fw_download(struct be_adapter *adapter,
}
if (change_status == LANCER_FW_RESET_NEEDED) {
- status = lancer_fw_reset(adapter);
+ status = lancer_physdev_ctrl(adapter,
+ PHYSDEV_CONTROL_FW_RESET_MASK);
if (status) {
dev_err(&adapter->pdev->dev,
"Adapter busy for FW reset.\n"
@@ -3779,6 +3745,10 @@ int be_load_fw(struct be_adapter *adapter, u8 *fw_file)
else
status = be_fw_download(adapter, fw);
+ if (!status)
+ be_cmd_get_fw_ver(adapter, adapter->fw_ver,
+ adapter->fw_on_flash);
+
fw_exit:
release_firmware(fw);
return status;
@@ -4101,6 +4071,7 @@ static int be_get_initial_config(struct be_adapter *adapter)
static int lancer_recover_func(struct be_adapter *adapter)
{
+ struct device *dev = &adapter->pdev->dev;
int status;
status = lancer_test_and_set_rdy_state(adapter);
@@ -4112,8 +4083,7 @@ static int lancer_recover_func(struct be_adapter *adapter)
be_clear(adapter);
- adapter->hw_error = false;
- adapter->fw_timeout = false;
+ be_clear_all_error(adapter);
status = be_setup(adapter);
if (status)
@@ -4125,13 +4095,13 @@ static int lancer_recover_func(struct be_adapter *adapter)
goto err;
}
- dev_err(&adapter->pdev->dev,
- "Adapter SLIPORT recovery succeeded\n");
+ dev_err(dev, "Error recovery successful\n");
return 0;
err:
- if (adapter->eeh_error)
- dev_err(&adapter->pdev->dev,
- "Adapter SLIPORT recovery failed\n");
+ if (status == -EAGAIN)
+ dev_err(dev, "Waiting for resource provisioning\n");
+ else
+ dev_err(dev, "Error recovery failed\n");
return status;
}
@@ -4140,28 +4110,27 @@ static void be_func_recovery_task(struct work_struct *work)
{
struct be_adapter *adapter =
container_of(work, struct be_adapter, func_recovery_work.work);
- int status;
+ int status = 0;
be_detect_error(adapter);
if (adapter->hw_error && lancer_chip(adapter)) {
- if (adapter->eeh_error)
- goto out;
-
rtnl_lock();
netif_device_detach(adapter->netdev);
rtnl_unlock();
status = lancer_recover_func(adapter);
-
if (!status)
netif_device_attach(adapter->netdev);
}
-out:
- schedule_delayed_work(&adapter->func_recovery_work,
- msecs_to_jiffies(1000));
+ /* In Lancer, for all errors other than provisioning error (-EAGAIN),
+ * no need to attempt further recovery.
+ */
+ if (!status || status == -EAGAIN)
+ schedule_delayed_work(&adapter->func_recovery_work,
+ msecs_to_jiffies(1000));
}
static void be_worker(struct work_struct *work)
@@ -4207,9 +4176,10 @@ reschedule:
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
}
+/* If any VFs are already enabled don't FLR the PF */
static bool be_reset_required(struct be_adapter *adapter)
{
- return be_find_vfs(adapter, ENABLED) > 0 ? false : true;
+ return pci_num_vf(adapter->pdev) ? false : true;
}
static char *mc_name(struct be_adapter *adapter)
@@ -4266,6 +4236,9 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
netdev->features |= NETIF_F_HIGHDMA;
} else {
status = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (!status)
+ status = dma_set_coherent_mask(&pdev->dev,
+ DMA_BIT_MASK(32));
if (status) {
dev_err(&pdev->dev, "Could not set PCI DMA Mask\n");
goto free_netdev;
@@ -4444,20 +4417,19 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
dev_err(&adapter->pdev->dev, "EEH error detected\n");
- adapter->eeh_error = true;
-
- cancel_delayed_work_sync(&adapter->func_recovery_work);
+ if (!adapter->eeh_error) {
+ adapter->eeh_error = true;
- rtnl_lock();
- netif_device_detach(netdev);
- rtnl_unlock();
+ cancel_delayed_work_sync(&adapter->func_recovery_work);
- if (netif_running(netdev)) {
rtnl_lock();
- be_close(netdev);
+ netif_device_detach(netdev);
+ if (netif_running(netdev))
+ be_close(netdev);
rtnl_unlock();
+
+ be_clear(adapter);
}
- be_clear(adapter);
if (state == pci_channel_io_perm_failure)
return PCI_ERS_RESULT_DISCONNECT;
@@ -4482,7 +4454,6 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
int status;
dev_info(&adapter->pdev->dev, "EEH reset\n");
- be_clear_all_error(adapter);
status = pci_enable_device(pdev);
if (status)
@@ -4500,6 +4471,7 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev)
return PCI_ERS_RESULT_DISCONNECT;
pci_cleanup_aer_uncorrect_error_status(pdev);
+ be_clear_all_error(adapter);
return PCI_ERS_RESULT_RECOVERED;
}
diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c
index 5722bc6..cf579fb 100644
--- a/drivers/net/ethernet/ethoc.c
+++ b/drivers/net/ethernet/ethoc.c
@@ -1147,8 +1147,6 @@ static int ethoc_remove(struct platform_device *pdev)
struct net_device *netdev = platform_get_drvdata(pdev);
struct ethoc *priv = netdev_priv(netdev);
- platform_set_drvdata(pdev, NULL);
-
if (netdev) {
netif_napi_del(&priv->napi);
phy_disconnect(priv->phy);
diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig
index b8974b9..5918c68 100644
--- a/drivers/net/ethernet/faraday/Kconfig
+++ b/drivers/net/ethernet/faraday/Kconfig
@@ -21,7 +21,6 @@ if NET_VENDOR_FARADAY
config FTMAC100
tristate "Faraday FTMAC100 10/100 Ethernet support"
depends on ARM
- select NET_CORE
select MII
---help---
This driver supports the FTMAC100 10/100 Ethernet controller
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 21b85fb..934e1ae 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -1311,7 +1311,6 @@ err_ioremap:
release_resource(priv->res);
err_req_mem:
netif_napi_del(&priv->napi);
- platform_set_drvdata(pdev, NULL);
free_netdev(netdev);
err_alloc_etherdev:
return err;
@@ -1335,7 +1334,6 @@ static int __exit ftgmac100_remove(struct platform_device *pdev)
release_resource(priv->res);
netif_napi_del(&priv->napi);
- platform_set_drvdata(pdev, NULL);
free_netdev(netdev);
return 0;
}
diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c
index a6eda8d..4658f4c 100644
--- a/drivers/net/ethernet/faraday/ftmac100.c
+++ b/drivers/net/ethernet/faraday/ftmac100.c
@@ -1149,7 +1149,6 @@ err_ioremap:
release_resource(priv->res);
err_req_mem:
netif_napi_del(&priv->napi);
- platform_set_drvdata(pdev, NULL);
free_netdev(netdev);
err_alloc_etherdev:
return err;
@@ -1169,7 +1168,6 @@ static int __exit ftmac100_remove(struct platform_device *pdev)
release_resource(priv->res);
netif_napi_del(&priv->napi);
- platform_set_drvdata(pdev, NULL);
free_netdev(netdev);
return 0;
}
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 9ce5b71..e3ed6c5 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -272,9 +272,10 @@ struct fec_enet_private {
int hwts_tx_en;
struct timer_list time_keep;
struct fec_enet_delayed_work delay_work;
+ struct regulator *reg_phy;
};
-void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev);
+void fec_ptp_init(struct platform_device *pdev);
void fec_ptp_start_cyclecounter(struct net_device *ndev);
int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd);
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index aff0310..46f2544 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -53,7 +53,6 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_net.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/regulator/consumer.h>
#include <asm/cacheflush.h>
@@ -87,6 +86,8 @@
#define FEC_QUIRK_HAS_GBIT (1 << 3)
/* Controller has extend desc buffer */
#define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4)
+/* Controller has hardware checksum support */
+#define FEC_QUIRK_HAS_CSUM (1 << 5)
static struct platform_device_id fec_devtype[] = {
{
@@ -105,9 +106,9 @@ static struct platform_device_id fec_devtype[] = {
}, {
.name = "imx6q-fec",
.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
- FEC_QUIRK_HAS_BUFDESC_EX,
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM,
}, {
- .name = "mvf-fec",
+ .name = "mvf600-fec",
.driver_data = FEC_QUIRK_ENET_MAC,
}, {
/* sentinel */
@@ -120,7 +121,7 @@ enum imx_fec_type {
IMX27_FEC, /* runs on i.mx27/35/51 */
IMX28_FEC,
IMX6Q_FEC,
- MVF_FEC,
+ MVF600_FEC,
};
static const struct of_device_id fec_dt_ids[] = {
@@ -128,7 +129,7 @@ static const struct of_device_id fec_dt_ids[] = {
{ .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], },
{ .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], },
{ .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], },
- { .compatible = "fsl,mvf-fec", .data = &fec_devtype[MVF_FEC], },
+ { .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fec_dt_ids);
@@ -241,7 +242,7 @@ static void *swap_buffer(void *bufaddr, int len)
int i;
unsigned int *buf = bufaddr;
- for (i = 0; i < (len + 3) / 4; i++, buf++)
+ for (i = 0; i < DIV_ROUND_UP(len, 4); i++, buf++)
*buf = cpu_to_be32(*buf);
return bufaddr;
@@ -449,7 +450,7 @@ fec_restart(struct net_device *ndev, int duplex)
netif_device_detach(ndev);
napi_disable(&fep->napi);
netif_stop_queue(ndev);
- netif_tx_lock(ndev);
+ netif_tx_lock_bh(ndev);
}
/* Whack a reset. We should wait for this. */
@@ -614,10 +615,10 @@ fec_restart(struct net_device *ndev, int duplex)
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
if (netif_running(ndev)) {
- netif_device_attach(ndev);
- napi_enable(&fep->napi);
+ netif_tx_unlock_bh(ndev);
netif_wake_queue(ndev);
- netif_tx_unlock(ndev);
+ napi_enable(&fep->napi);
+ netif_device_attach(ndev);
}
}
@@ -1036,6 +1037,18 @@ static void fec_get_mac(struct net_device *ndev)
iap = &tmpaddr[0];
}
+ /*
+ * 5) random mac address
+ */
+ if (!is_valid_ether_addr(iap)) {
+ /* Report it and use a random ethernet address instead */
+ netdev_err(ndev, "Invalid MAC address: %pM\n", iap);
+ eth_hw_addr_random(ndev);
+ netdev_info(ndev, "Using random MAC address: %pM\n",
+ ndev->dev_addr);
+ return;
+ }
+
memcpy(ndev->dev_addr, iap, ETH_ALEN);
/* Adjust MAC if using macaddr */
@@ -1422,6 +1435,17 @@ static int fec_enet_set_pauseparam(struct net_device *ndev,
return 0;
}
+static int fec_enet_nway_reset(struct net_device *dev)
+{
+ struct fec_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phydev = fep->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return genphy_restart_aneg(phydev);
+}
+
static const struct ethtool_ops fec_enet_ethtool_ops = {
.get_pauseparam = fec_enet_get_pauseparam,
.set_pauseparam = fec_enet_set_pauseparam,
@@ -1430,6 +1454,7 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.get_drvinfo = fec_enet_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ts_info = fec_enet_get_ts_info,
+ .nway_reset = fec_enet_nway_reset,
};
static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -1744,6 +1769,8 @@ static const struct net_device_ops fec_netdev_ops = {
static int fec_enet_init(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
+ const struct platform_device_id *id_entry =
+ platform_get_device_id(fep->pdev);
struct bufdesc *cbd_base;
/* Allocate memory for buffer descriptors. */
@@ -1775,12 +1802,14 @@ static int fec_enet_init(struct net_device *ndev)
writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
- /* enable hw accelerator */
- ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
- | NETIF_F_RXCSUM);
- ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
- | NETIF_F_RXCSUM);
- fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
+ if (id_entry->driver_data & FEC_QUIRK_HAS_CSUM) {
+ /* enable hw accelerator */
+ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+ | NETIF_F_RXCSUM);
+ ndev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
+ | NETIF_F_RXCSUM);
+ fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
+ }
fec_restart(ndev, 0);
@@ -1835,8 +1864,6 @@ fec_probe(struct platform_device *pdev)
struct resource *r;
const struct of_device_id *of_id;
static int dev_id;
- struct pinctrl *pinctrl;
- struct regulator *reg_phy;
of_id = of_match_device(fec_dt_ids, &pdev->dev);
if (of_id)
@@ -1861,17 +1888,17 @@ fec_probe(struct platform_device *pdev)
(pdev->id_entry->driver_data & FEC_QUIRK_HAS_GBIT))
fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
- fep->hwp = devm_request_and_ioremap(&pdev->dev, r);
+ fep->hwp = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(fep->hwp)) {
+ ret = PTR_ERR(fep->hwp);
+ goto failed_ioremap;
+ }
+
fep->pdev = pdev;
fep->dev_id = dev_id++;
fep->bufdesc_ex = 0;
- if (!fep->hwp) {
- ret = -ENOMEM;
- goto failed_ioremap;
- }
-
platform_set_drvdata(pdev, ndev);
ret = of_get_phy_mode(pdev->dev.of_node);
@@ -1885,12 +1912,6 @@ fec_probe(struct platform_device *pdev)
fep->phy_interface = ret;
}
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- ret = PTR_ERR(pinctrl);
- goto failed_pin;
- }
-
fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(fep->clk_ipg)) {
ret = PTR_ERR(fep->clk_ipg);
@@ -1921,20 +1942,22 @@ fec_probe(struct platform_device *pdev)
clk_prepare_enable(fep->clk_enet_out);
clk_prepare_enable(fep->clk_ptp);
- reg_phy = devm_regulator_get(&pdev->dev, "phy");
- if (!IS_ERR(reg_phy)) {
- ret = regulator_enable(reg_phy);
+ fep->reg_phy = devm_regulator_get(&pdev->dev, "phy");
+ if (!IS_ERR(fep->reg_phy)) {
+ ret = regulator_enable(fep->reg_phy);
if (ret) {
dev_err(&pdev->dev,
"Failed to enable phy regulator: %d\n", ret);
goto failed_regulator;
}
+ } else {
+ fep->reg_phy = NULL;
}
fec_reset_phy(pdev);
if (fep->bufdesc_ex)
- fec_ptp_init(ndev, pdev);
+ fec_ptp_init(pdev);
ret = fec_enet_init(ndev);
if (ret)
@@ -1978,19 +2001,20 @@ fec_probe(struct platform_device *pdev)
failed_register:
fec_enet_mii_remove(fep);
failed_mii_init:
-failed_init:
+failed_irq:
for (i = 0; i < FEC_IRQ_NUM; i++) {
irq = platform_get_irq(pdev, i);
if (irq > 0)
free_irq(irq, ndev);
}
-failed_irq:
+failed_init:
+ if (fep->reg_phy)
+ regulator_disable(fep->reg_phy);
failed_regulator:
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
clk_disable_unprepare(fep->clk_enet_out);
clk_disable_unprepare(fep->clk_ptp);
-failed_pin:
failed_clk:
failed_ioremap:
free_netdev(ndev);
@@ -2009,21 +2033,21 @@ fec_drv_remove(struct platform_device *pdev)
unregister_netdev(ndev);
fec_enet_mii_remove(fep);
del_timer_sync(&fep->time_keep);
+ for (i = 0; i < FEC_IRQ_NUM; i++) {
+ int irq = platform_get_irq(pdev, i);
+ if (irq > 0)
+ free_irq(irq, ndev);
+ }
+ if (fep->reg_phy)
+ regulator_disable(fep->reg_phy);
clk_disable_unprepare(fep->clk_ptp);
if (fep->ptp_clock)
ptp_clock_unregister(fep->ptp_clock);
clk_disable_unprepare(fep->clk_enet_out);
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
- for (i = 0; i < FEC_IRQ_NUM; i++) {
- int irq = platform_get_irq(pdev, i);
- if (irq > 0)
- free_irq(irq, ndev);
- }
free_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
@@ -2042,6 +2066,9 @@ fec_suspend(struct device *dev)
clk_disable_unprepare(fep->clk_ahb);
clk_disable_unprepare(fep->clk_ipg);
+ if (fep->reg_phy)
+ regulator_disable(fep->reg_phy);
+
return 0;
}
@@ -2050,6 +2077,13 @@ fec_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
+ int ret;
+
+ if (fep->reg_phy) {
+ ret = regulator_enable(fep->reg_phy);
+ if (ret)
+ return ret;
+ }
clk_prepare_enable(fep->clk_enet_out);
clk_prepare_enable(fep->clk_ahb);
diff --git a/drivers/net/ethernet/freescale/fec_mpc52xx.c b/drivers/net/ethernet/freescale/fec_mpc52xx.c
index 9bc15e2..9947765 100644
--- a/drivers/net/ethernet/freescale/fec_mpc52xx.c
+++ b/drivers/net/ethernet/freescale/fec_mpc52xx.c
@@ -981,7 +981,7 @@ static int mpc52xx_fec_probe(struct platform_device *op)
goto err_node;
/* We're done ! */
- dev_set_drvdata(&op->dev, ndev);
+ platform_set_drvdata(op, ndev);
netdev_info(ndev, "%s MAC %pM\n",
op->dev.of_node->full_name, ndev->dev_addr);
@@ -1010,7 +1010,7 @@ mpc52xx_fec_remove(struct platform_device *op)
struct net_device *ndev;
struct mpc52xx_fec_priv *priv;
- ndev = dev_get_drvdata(&op->dev);
+ ndev = platform_get_drvdata(op);
priv = netdev_priv(ndev);
unregister_netdev(ndev);
@@ -1030,14 +1030,13 @@ mpc52xx_fec_remove(struct platform_device *op)
free_netdev(ndev);
- dev_set_drvdata(&op->dev, NULL);
return 0;
}
#ifdef CONFIG_PM
static int mpc52xx_fec_of_suspend(struct platform_device *op, pm_message_t state)
{
- struct net_device *dev = dev_get_drvdata(&op->dev);
+ struct net_device *dev = platform_get_drvdata(op);
if (netif_running(dev))
mpc52xx_fec_close(dev);
@@ -1047,7 +1046,7 @@ static int mpc52xx_fec_of_suspend(struct platform_device *op, pm_message_t state
static int mpc52xx_fec_of_resume(struct platform_device *op)
{
- struct net_device *dev = dev_get_drvdata(&op->dev);
+ struct net_device *dev = platform_get_drvdata(op);
mpc52xx_fec_hw_init(dev);
mpc52xx_fec_reset_stats(dev);
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 25fc960..5007e4f 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -347,8 +347,9 @@ static void fec_time_keep(unsigned long _data)
* cyclecounter init routine and exits.
*/
-void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev)
+void fec_ptp_init(struct platform_device *pdev)
{
+ struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev);
fep->ptp_caps.owner = THIS_MODULE;
diff --git a/drivers/net/ethernet/freescale/fs_enet/Kconfig b/drivers/net/ethernet/freescale/fs_enet/Kconfig
index 268414d..be92229 100644
--- a/drivers/net/ethernet/freescale/fs_enet/Kconfig
+++ b/drivers/net/ethernet/freescale/fs_enet/Kconfig
@@ -1,7 +1,6 @@
config FS_ENET
tristate "Freescale Ethernet Driver"
depends on NET_VENDOR_FREESCALE && (CPM1 || CPM2 || PPC_MPC512x)
- select NET_CORE
select MII
select PHYLIB
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index edc1200..8de53a1 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -1048,7 +1048,7 @@ static int fs_enet_probe(struct platform_device *ofdev)
}
SET_NETDEV_DEV(ndev, &ofdev->dev);
- dev_set_drvdata(&ofdev->dev, ndev);
+ platform_set_drvdata(ofdev, ndev);
fep = netdev_priv(ndev);
fep->dev = &ofdev->dev;
@@ -1106,7 +1106,6 @@ out_cleanup_data:
fep->ops->cleanup_data(ndev);
out_free_dev:
free_netdev(ndev);
- dev_set_drvdata(&ofdev->dev, NULL);
out_put:
of_node_put(fpi->phy_node);
out_free_fpi:
@@ -1116,7 +1115,7 @@ out_free_fpi:
static int fs_enet_remove(struct platform_device *ofdev)
{
- struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct net_device *ndev = platform_get_drvdata(ofdev);
struct fs_enet_private *fep = netdev_priv(ndev);
unregister_netdev(ndev);
diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
index 2bafbd3..844ecfa 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
@@ -179,7 +179,7 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev)
}
new_bus->parent = &ofdev->dev;
- dev_set_drvdata(&ofdev->dev, new_bus);
+ platform_set_drvdata(ofdev, new_bus);
ret = of_mdiobus_register(new_bus, ofdev->dev.of_node);
if (ret)
@@ -188,7 +188,6 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev)
return 0;
out_free_irqs:
- dev_set_drvdata(&ofdev->dev, NULL);
kfree(new_bus->irq);
out_unmap_regs:
iounmap(bitbang->dir);
@@ -202,11 +201,10 @@ out:
static int fs_enet_mdio_remove(struct platform_device *ofdev)
{
- struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct mii_bus *bus = platform_get_drvdata(ofdev);
struct bb_info *bitbang = bus->priv;
mdiobus_unregister(bus);
- dev_set_drvdata(&ofdev->dev, NULL);
kfree(bus->irq);
free_mdio_bitbang(bus);
iounmap(bitbang->dir);
diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
index 18e8ef2..2f1c46a 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c
@@ -180,7 +180,7 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev)
}
new_bus->parent = &ofdev->dev;
- dev_set_drvdata(&ofdev->dev, new_bus);
+ platform_set_drvdata(ofdev, new_bus);
ret = of_mdiobus_register(new_bus, ofdev->dev.of_node);
if (ret)
@@ -189,7 +189,6 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev)
return 0;
out_free_irqs:
- dev_set_drvdata(&ofdev->dev, NULL);
kfree(new_bus->irq);
out_unmap_regs:
iounmap(fec->fecp);
@@ -204,11 +203,10 @@ out:
static int fs_enet_mdio_remove(struct platform_device *ofdev)
{
- struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct mii_bus *bus = platform_get_drvdata(ofdev);
struct fec_info *fec = bus->priv;
mdiobus_unregister(bus);
- dev_set_drvdata(&ofdev->dev, NULL);
kfree(bus->irq);
iounmap(fec->fecp);
kfree(fec);
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 2375a01..8d2db7b 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -128,6 +128,7 @@ static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_configure_serdes(struct net_device *dev);
static int gfar_poll(struct napi_struct *napi, int budget);
+static int gfar_poll_sq(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void gfar_netpoll(struct net_device *dev);
#endif
@@ -1000,7 +1001,7 @@ static int gfar_probe(struct platform_device *ofdev)
spin_lock_init(&priv->bflock);
INIT_WORK(&priv->reset_task, gfar_reset_task);
- dev_set_drvdata(&ofdev->dev, priv);
+ platform_set_drvdata(ofdev, priv);
regs = priv->gfargrp[0].regs;
gfar_detect_errata(priv);
@@ -1038,9 +1039,13 @@ static int gfar_probe(struct platform_device *ofdev)
dev->ethtool_ops = &gfar_ethtool_ops;
/* Register for napi ...We are registering NAPI for each grp */
- for (i = 0; i < priv->num_grps; i++)
- netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll,
+ if (priv->mode == SQ_SG_MODE)
+ netif_napi_add(dev, &priv->gfargrp[0].napi, gfar_poll_sq,
GFAR_DEV_WEIGHT);
+ else
+ for (i = 0; i < priv->num_grps; i++)
+ netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll,
+ GFAR_DEV_WEIGHT);
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
@@ -1240,15 +1245,13 @@ register_fail:
static int gfar_remove(struct platform_device *ofdev)
{
- struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
+ struct gfar_private *priv = platform_get_drvdata(ofdev);
if (priv->phy_node)
of_node_put(priv->phy_node);
if (priv->tbi_node)
of_node_put(priv->tbi_node);
- dev_set_drvdata(&ofdev->dev, NULL);
-
unregister_netdev(priv->ndev);
unmap_group_regs(priv);
free_gfar_dev(priv);
@@ -2825,6 +2828,48 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
return howmany;
}
+static int gfar_poll_sq(struct napi_struct *napi, int budget)
+{
+ struct gfar_priv_grp *gfargrp =
+ container_of(napi, struct gfar_priv_grp, napi);
+ struct gfar __iomem *regs = gfargrp->regs;
+ struct gfar_priv_tx_q *tx_queue = gfargrp->priv->tx_queue[0];
+ struct gfar_priv_rx_q *rx_queue = gfargrp->priv->rx_queue[0];
+ int work_done = 0;
+
+ /* Clear IEVENT, so interrupts aren't called again
+ * because of the packets that have already arrived
+ */
+ gfar_write(&regs->ievent, IEVENT_RTX_MASK);
+
+ /* run Tx cleanup to completion */
+ if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx])
+ gfar_clean_tx_ring(tx_queue);
+
+ work_done = gfar_clean_rx_ring(rx_queue, budget);
+
+ if (work_done < budget) {
+ napi_complete(napi);
+ /* Clear the halt bit in RSTAT */
+ gfar_write(&regs->rstat, gfargrp->rstat);
+
+ gfar_write(&regs->imask, IMASK_DEFAULT);
+
+ /* If we are coalescing interrupts, update the timer
+ * Otherwise, clear it
+ */
+ gfar_write(&regs->txic, 0);
+ if (likely(tx_queue->txcoalescing))
+ gfar_write(&regs->txic, tx_queue->txic);
+
+ gfar_write(&regs->rxic, 0);
+ if (unlikely(rx_queue->rxcoalescing))
+ gfar_write(&regs->rxic, rx_queue->rxic);
+ }
+
+ return work_done;
+}
+
static int gfar_poll(struct napi_struct *napi, int budget)
{
struct gfar_priv_grp *gfargrp =
diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c
index 576e4b8..098f133 100644
--- a/drivers/net/ethernet/freescale/gianfar_ptp.c
+++ b/drivers/net/ethernet/freescale/gianfar_ptp.c
@@ -519,11 +519,12 @@ static int gianfar_ptp_probe(struct platform_device *dev)
}
gfar_phc_index = ptp_clock_index(etsects->clock);
- dev_set_drvdata(&dev->dev, etsects);
+ platform_set_drvdata(dev, etsects);
return 0;
no_clock:
+ iounmap(etsects->regs);
no_ioremap:
release_resource(etsects->rsrc);
no_resource:
@@ -536,7 +537,7 @@ no_memory:
static int gianfar_ptp_remove(struct platform_device *dev)
{
- struct etsects *etsects = dev_get_drvdata(&dev->dev);
+ struct etsects *etsects = platform_get_drvdata(dev);
gfar_write(&etsects->regs->tmr_temask, 0);
gfar_write(&etsects->regs->tmr_ctrl, 0);
diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c
index e04c598..3c43dac 100644
--- a/drivers/net/ethernet/freescale/ucc_geth.c
+++ b/drivers/net/ethernet/freescale/ucc_geth.c
@@ -3564,7 +3564,7 @@ static void ucc_geth_timeout(struct net_device *dev)
static int ucc_geth_suspend(struct platform_device *ofdev, pm_message_t state)
{
- struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct net_device *ndev = platform_get_drvdata(ofdev);
struct ucc_geth_private *ugeth = netdev_priv(ndev);
if (!netif_running(ndev))
@@ -3592,7 +3592,7 @@ static int ucc_geth_suspend(struct platform_device *ofdev, pm_message_t state)
static int ucc_geth_resume(struct platform_device *ofdev)
{
- struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct net_device *ndev = platform_get_drvdata(ofdev);
struct ucc_geth_private *ugeth = netdev_priv(ndev);
int err;
diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c
index 418068b..c1b6e7e 100644
--- a/drivers/net/ethernet/freescale/xgmac_mdio.c
+++ b/drivers/net/ethernet/freescale/xgmac_mdio.c
@@ -227,7 +227,7 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
goto err_registration;
}
- dev_set_drvdata(&pdev->dev, bus);
+ platform_set_drvdata(pdev, bus);
return 0;
@@ -242,7 +242,7 @@ err_ioremap:
static int xgmac_mdio_remove(struct platform_device *pdev)
{
- struct mii_bus *bus = dev_get_drvdata(&pdev->dev);
+ struct mii_bus *bus = platform_get_drvdata(pdev);
mdiobus_unregister(bus);
iounmap(bus->priv);
diff --git a/drivers/net/ethernet/ibm/Kconfig b/drivers/net/ethernet/ibm/Kconfig
index 6529d31..563a1ac 100644
--- a/drivers/net/ethernet/ibm/Kconfig
+++ b/drivers/net/ethernet/ibm/Kconfig
@@ -5,8 +5,7 @@
config NET_VENDOR_IBM
bool "IBM devices"
default y
- depends on MCA || PPC_PSERIES || PPC_PSERIES || PPC_DCR || \
- (IBMEBUS && SPARSEMEM)
+ depends on PPC_PSERIES || PPC_DCR || (IBMEBUS && SPARSEMEM)
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 90ea0b1..0605e76 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -3289,7 +3289,7 @@ static int ehea_probe_adapter(struct platform_device *dev,
adapter->pd = EHEA_PD_ID;
- dev_set_drvdata(&dev->dev, adapter);
+ platform_set_drvdata(dev, adapter);
/* initialize adapter and ports */
@@ -3360,7 +3360,7 @@ out:
static int ehea_remove(struct platform_device *dev)
{
- struct ehea_adapter *adapter = dev_get_drvdata(&dev->dev);
+ struct ehea_adapter *adapter = platform_get_drvdata(dev);
int i;
for (i = 0; i < EHEA_MAX_PORTS; i++)
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 4989481..d300a0c 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -359,10 +359,26 @@ static int emac_reset(struct emac_instance *dev)
}
#ifdef CONFIG_PPC_DCR_NATIVE
- /* Enable internal clock source */
- if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
- dcri_clrset(SDR0, SDR0_ETH_CFG,
- 0, SDR0_ETH_CFG_ECS << dev->cell_index);
+ /*
+ * PPC460EX/GT Embedded Processor Advanced User's Manual
+ * section 28.10.1 Mode Register 0 (EMACx_MR0) states:
+ * Note: The PHY must provide a TX Clk in order to perform a soft reset
+ * of the EMAC. If none is present, select the internal clock
+ * (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1).
+ * After a soft reset, select the external clock.
+ */
+ if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
+ if (dev->phy_address == 0xffffffff &&
+ dev->phy_map == 0xffffffff) {
+ /* No PHY: select internal loop clock before reset */
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
+ 0, SDR0_ETH_CFG_ECS << dev->cell_index);
+ } else {
+ /* PHY present: select external clock before reset */
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
+ SDR0_ETH_CFG_ECS << dev->cell_index, 0);
+ }
+ }
#endif
out_be32(&p->mr0, EMAC_MR0_SRST);
@@ -370,10 +386,14 @@ static int emac_reset(struct emac_instance *dev)
--n;
#ifdef CONFIG_PPC_DCR_NATIVE
- /* Enable external clock source */
- if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX))
- dcri_clrset(SDR0, SDR0_ETH_CFG,
- SDR0_ETH_CFG_ECS << dev->cell_index, 0);
+ if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
+ if (dev->phy_address == 0xffffffff &&
+ dev->phy_map == 0xffffffff) {
+ /* No PHY: restore external clock source after reset */
+ dcri_clrset(SDR0, SDR0_ETH_CFG,
+ SDR0_ETH_CFG_ECS << dev->cell_index, 0);
+ }
+ }
#endif
if (n) {
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index 610ed223..856ea66 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -696,7 +696,7 @@ static int mal_probe(struct platform_device *ofdev)
/* Advertise this instance to the rest of the world */
wmb();
- dev_set_drvdata(&ofdev->dev, mal);
+ platform_set_drvdata(ofdev, mal);
mal_dbg_register(mal);
@@ -722,7 +722,7 @@ static int mal_probe(struct platform_device *ofdev)
static int mal_remove(struct platform_device *ofdev)
{
- struct mal_instance *mal = dev_get_drvdata(&ofdev->dev);
+ struct mal_instance *mal = platform_get_drvdata(ofdev);
MAL_DBG(mal, "remove" NL);
@@ -735,8 +735,6 @@ static int mal_remove(struct platform_device *ofdev)
"mal%d: commac list is not empty on remove!\n",
mal->index);
- dev_set_drvdata(&ofdev->dev, NULL);
-
free_irq(mal->serr_irq, mal);
free_irq(mal->txde_irq, mal);
free_irq(mal->txeob_irq, mal);
diff --git a/drivers/net/ethernet/ibm/emac/rgmii.c b/drivers/net/ethernet/ibm/emac/rgmii.c
index 3925176..c47e23d 100644
--- a/drivers/net/ethernet/ibm/emac/rgmii.c
+++ b/drivers/net/ethernet/ibm/emac/rgmii.c
@@ -95,7 +95,7 @@ static inline u32 rgmii_mode_mask(int mode, int input)
int rgmii_attach(struct platform_device *ofdev, int input, int mode)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p = dev->base;
RGMII_DBG(dev, "attach(%d)" NL, input);
@@ -124,7 +124,7 @@ int rgmii_attach(struct platform_device *ofdev, int input, int mode)
void rgmii_set_speed(struct platform_device *ofdev, int input, int speed)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p = dev->base;
u32 ssr;
@@ -146,7 +146,7 @@ void rgmii_set_speed(struct platform_device *ofdev, int input, int speed)
void rgmii_get_mdio(struct platform_device *ofdev, int input)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p = dev->base;
u32 fer;
@@ -167,7 +167,7 @@ void rgmii_get_mdio(struct platform_device *ofdev, int input)
void rgmii_put_mdio(struct platform_device *ofdev, int input)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p = dev->base;
u32 fer;
@@ -188,7 +188,7 @@ void rgmii_put_mdio(struct platform_device *ofdev, int input)
void rgmii_detach(struct platform_device *ofdev, int input)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct rgmii_regs __iomem *p;
BUG_ON(!dev || dev->users == 0);
@@ -214,7 +214,7 @@ int rgmii_get_regs_len(struct platform_device *ofdev)
void *rgmii_dump_regs(struct platform_device *ofdev, void *buf)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
struct emac_ethtool_regs_subhdr *hdr = buf;
struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1);
@@ -279,7 +279,7 @@ static int rgmii_probe(struct platform_device *ofdev)
(dev->flags & EMAC_RGMII_FLAG_HAS_MDIO) ? "" : "out");
wmb();
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
return 0;
@@ -291,9 +291,7 @@ static int rgmii_probe(struct platform_device *ofdev)
static int rgmii_remove(struct platform_device *ofdev)
{
- struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-
- dev_set_drvdata(&ofdev->dev, NULL);
+ struct rgmii_instance *dev = platform_get_drvdata(ofdev);
WARN_ON(dev->users != 0);
diff --git a/drivers/net/ethernet/ibm/emac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c
index 795f139..c231a4a 100644
--- a/drivers/net/ethernet/ibm/emac/tah.c
+++ b/drivers/net/ethernet/ibm/emac/tah.c
@@ -25,7 +25,7 @@
int tah_attach(struct platform_device *ofdev, int channel)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
mutex_lock(&dev->lock);
/* Reset has been done at probe() time... nothing else to do for now */
@@ -37,7 +37,7 @@ int tah_attach(struct platform_device *ofdev, int channel)
void tah_detach(struct platform_device *ofdev, int channel)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
mutex_lock(&dev->lock);
--dev->users;
@@ -46,7 +46,7 @@ void tah_detach(struct platform_device *ofdev, int channel)
void tah_reset(struct platform_device *ofdev)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
struct tah_regs __iomem *p = dev->base;
int n;
@@ -74,7 +74,7 @@ int tah_get_regs_len(struct platform_device *ofdev)
void *tah_dump_regs(struct platform_device *ofdev, void *buf)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
struct emac_ethtool_regs_subhdr *hdr = buf;
struct tah_regs *regs = (struct tah_regs *)(hdr + 1);
@@ -118,7 +118,7 @@ static int tah_probe(struct platform_device *ofdev)
goto err_free;
}
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
/* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
tah_reset(ofdev);
@@ -137,9 +137,7 @@ static int tah_probe(struct platform_device *ofdev)
static int tah_remove(struct platform_device *ofdev)
{
- struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
-
- dev_set_drvdata(&ofdev->dev, NULL);
+ struct tah_instance *dev = platform_get_drvdata(ofdev);
WARN_ON(dev->users != 0);
diff --git a/drivers/net/ethernet/ibm/emac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c
index f91202f..4cdf286 100644
--- a/drivers/net/ethernet/ibm/emac/zmii.c
+++ b/drivers/net/ethernet/ibm/emac/zmii.c
@@ -84,7 +84,7 @@ static inline u32 zmii_mode_mask(int mode, int input)
int zmii_attach(struct platform_device *ofdev, int input, int *mode)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
struct zmii_regs __iomem *p = dev->base;
ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode);
@@ -150,7 +150,7 @@ int zmii_attach(struct platform_device *ofdev, int input, int *mode)
void zmii_get_mdio(struct platform_device *ofdev, int input)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
u32 fer;
ZMII_DBG2(dev, "get_mdio(%d)" NL, input);
@@ -163,7 +163,7 @@ void zmii_get_mdio(struct platform_device *ofdev, int input)
void zmii_put_mdio(struct platform_device *ofdev, int input)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
ZMII_DBG2(dev, "put_mdio(%d)" NL, input);
mutex_unlock(&dev->lock);
@@ -172,7 +172,7 @@ void zmii_put_mdio(struct platform_device *ofdev, int input)
void zmii_set_speed(struct platform_device *ofdev, int input, int speed)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
u32 ssr;
mutex_lock(&dev->lock);
@@ -193,7 +193,7 @@ void zmii_set_speed(struct platform_device *ofdev, int input, int speed)
void zmii_detach(struct platform_device *ofdev, int input)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
BUG_ON(!dev || dev->users == 0);
@@ -218,7 +218,7 @@ int zmii_get_regs_len(struct platform_device *ofdev)
void *zmii_dump_regs(struct platform_device *ofdev, void *buf)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
struct emac_ethtool_regs_subhdr *hdr = buf;
struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1);
@@ -272,7 +272,7 @@ static int zmii_probe(struct platform_device *ofdev)
printk(KERN_INFO
"ZMII %s initialized\n", ofdev->dev.of_node->full_name);
wmb();
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
return 0;
@@ -284,9 +284,7 @@ static int zmii_probe(struct platform_device *ofdev)
static int zmii_remove(struct platform_device *ofdev)
{
- struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
-
- dev_set_drvdata(&ofdev->dev, NULL);
+ struct zmii_instance *dev = platform_get_drvdata(ofdev);
WARN_ON(dev->users != 0);
diff --git a/drivers/net/ethernet/icplus/Kconfig b/drivers/net/ethernet/icplus/Kconfig
index 5119ef1..14a66e9 100644
--- a/drivers/net/ethernet/icplus/Kconfig
+++ b/drivers/net/ethernet/icplus/Kconfig
@@ -5,7 +5,6 @@
config IP1000
tristate "IP1000 Gigabit Ethernet support"
depends on PCI
- select NET_CORE
select MII
---help---
This driver supports IP1000 gigabit Ethernet cards.
diff --git a/drivers/net/ethernet/icplus/ipg.c b/drivers/net/ethernet/icplus/ipg.c
index 068d781..1fde90b 100644
--- a/drivers/net/ethernet/icplus/ipg.c
+++ b/drivers/net/ethernet/icplus/ipg.c
@@ -2298,15 +2298,4 @@ static struct pci_driver ipg_pci_driver = {
.remove = ipg_remove,
};
-static int __init ipg_init_module(void)
-{
- return pci_register_driver(&ipg_pci_driver);
-}
-
-static void __exit ipg_exit_module(void)
-{
- pci_unregister_driver(&ipg_pci_driver);
-}
-
-module_init(ipg_init_module);
-module_exit(ipg_exit_module);
+module_pci_driver(ipg_pci_driver);
diff --git a/drivers/net/ethernet/icplus/ipg.h b/drivers/net/ethernet/icplus/ipg.h
index 6ce0273..abb300a 100644
--- a/drivers/net/ethernet/icplus/ipg.h
+++ b/drivers/net/ethernet/icplus/ipg.h
@@ -195,57 +195,57 @@ enum ipg_regs {
/* TFD data structure masks. */
/* TFDList, TFC */
-#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFF
-#define IPG_TFC_FRAMEID 0x000000000000FFFF
-#define IPG_TFC_WORDALIGN 0x0000000000030000
-#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000
-#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000
-#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000
-#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000
-#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000
-#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000
-#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000
-#define IPG_TFC_TXINDICATE 0x0000000000400000
-#define IPG_TFC_TXDMAINDICATE 0x0000000000800000
-#define IPG_TFC_FRAGCOUNT 0x000000000F000000
-#define IPG_TFC_VLANTAGINSERT 0x0000000010000000
-#define IPG_TFC_TFDDONE 0x0000000080000000
-#define IPG_TFC_VID 0x00000FFF00000000
-#define IPG_TFC_CFI 0x0000100000000000
-#define IPG_TFC_USERPRIORITY 0x0000E00000000000
+#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFFULL
+#define IPG_TFC_FRAMEID 0x000000000000FFFFULL
+#define IPG_TFC_WORDALIGN 0x0000000000030000ULL
+#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000ULL
+#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000ULL
+#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000ULL
+#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000ULL
+#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000ULL
+#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000ULL
+#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000ULL
+#define IPG_TFC_TXINDICATE 0x0000000000400000ULL
+#define IPG_TFC_TXDMAINDICATE 0x0000000000800000ULL
+#define IPG_TFC_FRAGCOUNT 0x000000000F000000ULL
+#define IPG_TFC_VLANTAGINSERT 0x0000000010000000ULL
+#define IPG_TFC_TFDDONE 0x0000000080000000ULL
+#define IPG_TFC_VID 0x00000FFF00000000ULL
+#define IPG_TFC_CFI 0x0000100000000000ULL
+#define IPG_TFC_USERPRIORITY 0x0000E00000000000ULL
/* TFDList, FragInfo */
-#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFF
-#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFF
-#define IPG_TFI_FRAGLEN 0xFFFF000000000000LL
+#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL
+#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFFULL
+#define IPG_TFI_FRAGLEN 0xFFFF000000000000ULL
/* RFD data structure masks. */
/* RFDList, RFS */
-#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFF
-#define IPG_RFS_RXFRAMELEN 0x000000000000FFFF
-#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000
-#define IPG_RFS_RXRUNTFRAME 0x0000000000020000
-#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000
-#define IPG_RFS_RXFCSERROR 0x0000000000080000
-#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000
-#define IPG_RFS_RXLENGTHERROR 0x0000000000200000
-#define IPG_RFS_VLANDETECTED 0x0000000000400000
-#define IPG_RFS_TCPDETECTED 0x0000000000800000
-#define IPG_RFS_TCPERROR 0x0000000001000000
-#define IPG_RFS_UDPDETECTED 0x0000000002000000
-#define IPG_RFS_UDPERROR 0x0000000004000000
-#define IPG_RFS_IPDETECTED 0x0000000008000000
-#define IPG_RFS_IPERROR 0x0000000010000000
-#define IPG_RFS_FRAMESTART 0x0000000020000000
-#define IPG_RFS_FRAMEEND 0x0000000040000000
-#define IPG_RFS_RFDDONE 0x0000000080000000
-#define IPG_RFS_TCI 0x0000FFFF00000000
+#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFFULL
+#define IPG_RFS_RXFRAMELEN 0x000000000000FFFFULL
+#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000ULL
+#define IPG_RFS_RXRUNTFRAME 0x0000000000020000ULL
+#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000ULL
+#define IPG_RFS_RXFCSERROR 0x0000000000080000ULL
+#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000ULL
+#define IPG_RFS_RXLENGTHERROR 0x0000000000200000ULL
+#define IPG_RFS_VLANDETECTED 0x0000000000400000ULL
+#define IPG_RFS_TCPDETECTED 0x0000000000800000ULL
+#define IPG_RFS_TCPERROR 0x0000000001000000ULL
+#define IPG_RFS_UDPDETECTED 0x0000000002000000ULL
+#define IPG_RFS_UDPERROR 0x0000000004000000ULL
+#define IPG_RFS_IPDETECTED 0x0000000008000000ULL
+#define IPG_RFS_IPERROR 0x0000000010000000ULL
+#define IPG_RFS_FRAMESTART 0x0000000020000000ULL
+#define IPG_RFS_FRAMEEND 0x0000000040000000ULL
+#define IPG_RFS_RFDDONE 0x0000000080000000ULL
+#define IPG_RFS_TCI 0x0000FFFF00000000ULL
/* RFDList, FragInfo */
-#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFF
-#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFF
-#define IPG_RFI_FRAGLEN 0xFFFF000000000000LL
+#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL
+#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFFULL
+#define IPG_RFI_FRAGLEN 0xFFFF000000000000ULL
/* I/O Register masks. */
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 05f7264..f0e7ed2 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -20,7 +20,6 @@ if NET_VENDOR_INTEL
config E100
tristate "Intel(R) PRO/100+ support"
depends on PCI
- select NET_CORE
select MII
---help---
This driver supports Intel(R) PRO/100 family of adapters.
diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index b71c850..895450e 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -66,17 +66,17 @@ static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
s32 ret_val;
if (hw->phy.media_type != e1000_media_type_copper) {
- phy->type = e1000_phy_none;
+ phy->type = e1000_phy_none;
return 0;
} else {
phy->ops.power_up = e1000_power_up_phy_copper;
phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan;
}
- phy->addr = 1;
- phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
- phy->reset_delay_us = 100;
- phy->type = e1000_phy_gg82563;
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
+ phy->type = e1000_phy_gg82563;
/* This can only be done after all function pointers are setup. */
ret_val = e1000e_get_phy_id(hw);
@@ -98,19 +98,19 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
u32 eecd = er32(EECD);
u16 size;
- nvm->opcode_bits = 8;
- nvm->delay_usec = 1;
+ nvm->opcode_bits = 8;
+ nvm->delay_usec = 1;
switch (nvm->override) {
case e1000_nvm_override_spi_large:
- nvm->page_size = 32;
+ nvm->page_size = 32;
nvm->address_bits = 16;
break;
case e1000_nvm_override_spi_small:
- nvm->page_size = 8;
+ nvm->page_size = 8;
nvm->address_bits = 8;
break;
default:
- nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+ nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
break;
}
@@ -128,7 +128,7 @@ static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
/* EEPROM access above 16k is unsupported */
if (size > 14)
size = 14;
- nvm->word_size = 1 << size;
+ nvm->word_size = 1 << size;
return 0;
}
@@ -859,7 +859,7 @@ static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
/* Transmit Arbitration Control 0 */
reg = er32(TARC(0));
- reg &= ~(0xF << 27); /* 30:27 */
+ reg &= ~(0xF << 27); /* 30:27 */
if (hw->phy.media_type != e1000_media_type_copper)
reg &= ~(1 << 20);
ew32(TARC(0), reg);
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index 7380442..4c303e2 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -77,24 +77,24 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
return 0;
}
- phy->addr = 1;
- phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
- phy->reset_delay_us = 100;
+ phy->addr = 1;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->reset_delay_us = 100;
- phy->ops.power_up = e1000_power_up_phy_copper;
- phy->ops.power_down = e1000_power_down_phy_copper_82571;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_82571;
switch (hw->mac.type) {
case e1000_82571:
case e1000_82572:
- phy->type = e1000_phy_igp_2;
+ phy->type = e1000_phy_igp_2;
break;
case e1000_82573:
- phy->type = e1000_phy_m88;
+ phy->type = e1000_phy_m88;
break;
case e1000_82574:
case e1000_82583:
- phy->type = e1000_phy_bm;
+ phy->type = e1000_phy_bm;
phy->ops.acquire = e1000_get_hw_semaphore_82574;
phy->ops.release = e1000_put_hw_semaphore_82574;
phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82574;
@@ -193,7 +193,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
/* EEPROM access above 16k is unsupported */
if (size > 14)
size = 14;
- nvm->word_size = 1 << size;
+ nvm->word_size = 1 << size;
break;
}
@@ -339,7 +339,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_hw *hw)
static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
- static int global_quad_port_a; /* global port a indication */
+ static int global_quad_port_a; /* global port a indication */
struct pci_dev *pdev = adapter->pdev;
int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
s32 rc;
@@ -1003,8 +1003,6 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
default:
break;
}
- if (ret_val)
- e_dbg("Cannot acquire MDIO ownership\n");
ctrl = er32(CTRL);
@@ -1015,7 +1013,9 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
switch (hw->mac.type) {
case e1000_82574:
case e1000_82583:
- e1000_put_hw_semaphore_82574(hw);
+ /* Release mutex only if the hw semaphore is acquired */
+ if (!ret_val)
+ e1000_put_hw_semaphore_82574(hw);
break;
default:
break;
@@ -1178,7 +1178,7 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
/* Transmit Arbitration Control 0 */
reg = er32(TARC(0));
- reg &= ~(0xF << 27); /* 30:27 */
+ reg &= ~(0xF << 27); /* 30:27 */
switch (hw->mac.type) {
case e1000_82571:
case e1000_82572:
@@ -1390,7 +1390,7 @@ bool e1000_check_phy_82574(struct e1000_hw *hw)
ret_val = e1e_rphy(hw, E1000_RECEIVE_ERROR_COUNTER, &receive_errors);
if (ret_val)
return false;
- if (receive_errors == E1000_RECEIVE_ERROR_MAX) {
+ if (receive_errors == E1000_RECEIVE_ERROR_MAX) {
ret_val = e1e_rphy(hw, E1000_BASE1000T_STATUS, &status_1kbt);
if (ret_val)
return false;
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index 7c8ca65..59c22bf 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -244,7 +244,7 @@ static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx)
mac->autoneg = 1;
adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;
break;
- case SPEED_1000 + DUPLEX_HALF: /* not supported */
+ case SPEED_1000 + DUPLEX_HALF: /* not supported */
default:
goto err_inval;
}
@@ -416,7 +416,7 @@ static void e1000_set_msglevel(struct net_device *netdev, u32 data)
static int e1000_get_regs_len(struct net_device __always_unused *netdev)
{
-#define E1000_REGS_LEN 32 /* overestimate */
+#define E1000_REGS_LEN 32 /* overestimate */
return E1000_REGS_LEN * sizeof(u32);
}
@@ -433,22 +433,22 @@ static void e1000_get_regs(struct net_device *netdev,
regs->version = (1 << 24) | (adapter->pdev->revision << 16) |
adapter->pdev->device;
- regs_buff[0] = er32(CTRL);
- regs_buff[1] = er32(STATUS);
+ regs_buff[0] = er32(CTRL);
+ regs_buff[1] = er32(STATUS);
- regs_buff[2] = er32(RCTL);
- regs_buff[3] = er32(RDLEN(0));
- regs_buff[4] = er32(RDH(0));
- regs_buff[5] = er32(RDT(0));
- regs_buff[6] = er32(RDTR);
+ regs_buff[2] = er32(RCTL);
+ regs_buff[3] = er32(RDLEN(0));
+ regs_buff[4] = er32(RDH(0));
+ regs_buff[5] = er32(RDT(0));
+ regs_buff[6] = er32(RDTR);
- regs_buff[7] = er32(TCTL);
- regs_buff[8] = er32(TDLEN(0));
- regs_buff[9] = er32(TDH(0));
+ regs_buff[7] = er32(TCTL);
+ regs_buff[8] = er32(TDLEN(0));
+ regs_buff[9] = er32(TDH(0));
regs_buff[10] = er32(TDT(0));
regs_buff[11] = er32(TIDV);
- regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */
+ regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */
/* ethtool doesn't use anything past this point, so all this
* code is likely legacy junk for apps that may or may not exist
@@ -1379,7 +1379,7 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
if (hw->phy.media_type == e1000_media_type_copper &&
hw->phy.type == e1000_phy_m88) {
- ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+ ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
} else {
/* Set the ILOS bit on the fiber Nic if half duplex link is
* detected.
@@ -1613,7 +1613,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
ew32(TDT(0), k);
e1e_flush();
msleep(200);
- time = jiffies; /* set the start time for the receive */
+ time = jiffies; /* set the start time for the receive */
good_cnt = 0;
/* receive the sent packets */
do {
@@ -1636,11 +1636,11 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
*/
} while ((good_cnt < 64) && !time_after(jiffies, time + 20));
if (good_cnt != 64) {
- ret_val = 13; /* ret_val is the same as mis-compare */
+ ret_val = 13; /* ret_val is the same as mis-compare */
break;
}
if (jiffies >= (time + 20)) {
- ret_val = 14; /* error code for time out error */
+ ret_val = 14; /* error code for time out error */
break;
}
}
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index 84850f7..a6f903a 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -402,13 +402,13 @@ struct e1000_phy_stats {
struct e1000_host_mng_dhcp_cookie {
u32 signature;
- u8 status;
- u8 reserved0;
+ u8 status;
+ u8 reserved0;
u16 vlan_id;
u32 reserved1;
u16 reserved2;
- u8 reserved3;
- u8 checksum;
+ u8 reserved3;
+ u8 checksum;
};
/* Host Interface "Rev 1" */
@@ -427,8 +427,8 @@ struct e1000_host_command_info {
/* Host Interface "Rev 2" */
struct e1000_host_mng_command_header {
- u8 command_id;
- u8 checksum;
+ u8 command_id;
+ u8 checksum;
u16 reserved1;
u16 reserved2;
u16 command_length;
@@ -549,7 +549,7 @@ struct e1000_mac_info {
u32 mta_shadow[MAX_MTA_REG];
u16 rar_entry_count;
- u8 forced_speed_duplex;
+ u8 forced_speed_duplex;
bool adaptive_ifs;
bool has_fwsm;
@@ -577,7 +577,7 @@ struct e1000_phy_info {
u32 addr;
u32 id;
- u32 reset_delay_us; /* in usec */
+ u32 reset_delay_us; /* in usec */
u32 revision;
enum e1000_media_type media_type;
@@ -636,11 +636,11 @@ struct e1000_dev_spec_82571 {
};
struct e1000_dev_spec_80003es2lan {
- bool mdic_wa_enable;
+ bool mdic_wa_enable;
};
struct e1000_shadow_ram {
- u16 value;
+ u16 value;
bool modified;
};
@@ -660,17 +660,17 @@ struct e1000_hw {
void __iomem *hw_addr;
void __iomem *flash_address;
- struct e1000_mac_info mac;
- struct e1000_fc_info fc;
- struct e1000_phy_info phy;
- struct e1000_nvm_info nvm;
- struct e1000_bus_info bus;
+ struct e1000_mac_info mac;
+ struct e1000_fc_info fc;
+ struct e1000_phy_info phy;
+ struct e1000_nvm_info nvm;
+ struct e1000_bus_info bus;
struct e1000_host_mng_dhcp_cookie mng_cookie;
union {
- struct e1000_dev_spec_82571 e82571;
+ struct e1000_dev_spec_82571 e82571;
struct e1000_dev_spec_80003es2lan e80003es2lan;
- struct e1000_dev_spec_ich8lan ich8lan;
+ struct e1000_dev_spec_ich8lan ich8lan;
} dev_spec;
};
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index ad9d8f2..9dde390 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -101,12 +101,12 @@ union ich8_hws_flash_regacc {
/* ICH Flash Protected Region */
union ich8_flash_protected_range {
struct ich8_pr {
- u32 base:13; /* 0:12 Protected Range Base */
- u32 reserved1:2; /* 13:14 Reserved */
- u32 rpe:1; /* 15 Read Protection Enable */
- u32 limit:13; /* 16:28 Protected Range Limit */
- u32 reserved2:2; /* 29:30 Reserved */
- u32 wpe:1; /* 31 Write Protection Enable */
+ u32 base:13; /* 0:12 Protected Range Base */
+ u32 reserved1:2; /* 13:14 Reserved */
+ u32 rpe:1; /* 15 Read Protection Enable */
+ u32 limit:13; /* 16:28 Protected Range Limit */
+ u32 reserved2:2; /* 29:30 Reserved */
+ u32 wpe:1; /* 31 Write Protection Enable */
} range;
u32 regval;
};
@@ -362,21 +362,21 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
struct e1000_phy_info *phy = &hw->phy;
s32 ret_val;
- phy->addr = 1;
- phy->reset_delay_us = 100;
-
- phy->ops.set_page = e1000_set_page_igp;
- phy->ops.read_reg = e1000_read_phy_reg_hv;
- phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
- phy->ops.read_reg_page = e1000_read_phy_reg_page_hv;
- phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
- phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
- phy->ops.write_reg = e1000_write_phy_reg_hv;
- phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
- phy->ops.write_reg_page = e1000_write_phy_reg_page_hv;
- phy->ops.power_up = e1000_power_up_phy_copper;
- phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
- phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ phy->addr = 1;
+ phy->reset_delay_us = 100;
+
+ phy->ops.set_page = e1000_set_page_igp;
+ phy->ops.read_reg = e1000_read_phy_reg_hv;
+ phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
+ phy->ops.read_reg_page = e1000_read_phy_reg_page_hv;
+ phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
+ phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
+ phy->ops.write_reg = e1000_write_phy_reg_hv;
+ phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
+ phy->ops.write_reg_page = e1000_write_phy_reg_page_hv;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
+ phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
phy->id = e1000_phy_unknown;
@@ -445,11 +445,11 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
s32 ret_val;
u16 i = 0;
- phy->addr = 1;
- phy->reset_delay_us = 100;
+ phy->addr = 1;
+ phy->reset_delay_us = 100;
- phy->ops.power_up = e1000_power_up_phy_copper;
- phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
+ phy->ops.power_up = e1000_power_up_phy_copper;
+ phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
/* We may need to do this twice - once for IGP and if that fails,
* we'll set BM func pointers and try again
@@ -457,7 +457,7 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
ret_val = e1000e_determine_phy_address(hw);
if (ret_val) {
phy->ops.write_reg = e1000e_write_phy_reg_bm;
- phy->ops.read_reg = e1000e_read_phy_reg_bm;
+ phy->ops.read_reg = e1000e_read_phy_reg_bm;
ret_val = e1000e_determine_phy_address(hw);
if (ret_val) {
e_dbg("Cannot determine PHY addr. Erroring out\n");
@@ -560,7 +560,7 @@ static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
/* Clear shadow ram */
for (i = 0; i < nvm->word_size; i++) {
dev_spec->shadow_ram[i].modified = false;
- dev_spec->shadow_ram[i].value = 0xFFFF;
+ dev_spec->shadow_ram[i].value = 0xFFFF;
}
return 0;
@@ -1012,7 +1012,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
hw->dev_spec.ich8lan.eee_lp_ability = 0;
if (!link)
- return 0; /* No link detected */
+ return 0; /* No link detected */
mac->get_link_status = false;
@@ -2816,7 +2816,7 @@ static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
s32 ret_val = -E1000_ERR_NVM;
u8 count = 0;
- if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+ if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
return -E1000_ERR_NVM;
flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) +
@@ -2939,7 +2939,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
* write to bank 0 etc. We also need to erase the segment that
* is going to be written
*/
- ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
+ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
if (ret_val) {
e_dbg("Could not detect valid bank, assuming bank 0\n");
bank = 0;
@@ -4073,7 +4073,7 @@ void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
{
u32 reg;
u16 data;
- u8 retry = 0;
+ u8 retry = 0;
if (hw->phy.type != e1000_phy_igp_3)
return;
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index a27e3bc..77f81cb 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1196,7 +1196,7 @@ static bool e1000_clean_tx_irq(struct e1000_ring *tx_ring)
while ((eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) &&
(count < tx_ring->count)) {
bool cleaned = false;
- rmb(); /* read buffer_info after eop_desc */
+ rmb(); /* read buffer_info after eop_desc */
for (; !cleaned; count++) {
tx_desc = E1000_TX_DESC(*tx_ring, i);
buffer_info = &tx_ring->buffer_info[i];
@@ -1385,7 +1385,7 @@ static bool e1000_clean_rx_irq_ps(struct e1000_ring *rx_ring, int *work_done,
skb_put(skb, l1);
goto copydone;
- } /* if */
+ } /* if */
}
for (j = 0; j < PS_PAGE_BUFFERS; j++) {
@@ -1800,7 +1800,7 @@ static irqreturn_t e1000_intr(int __always_unused irq, void *data)
u32 rctl, icr = er32(ICR);
if (!icr || test_bit(__E1000_DOWN, &adapter->state))
- return IRQ_NONE; /* Not our interrupt */
+ return IRQ_NONE; /* Not our interrupt */
/* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
* not set, then the adapter didn't send an interrupt
@@ -2487,7 +2487,7 @@ static unsigned int e1000_update_itr(u16 itr_setting, int packets, int bytes)
else if ((packets < 5) && (bytes > 512))
retval = low_latency;
break;
- case low_latency: /* 50 usec aka 20000 ints/s */
+ case low_latency: /* 50 usec aka 20000 ints/s */
if (bytes > 10000) {
/* this if handles the TSO accounting */
if (bytes / packets > 8000)
@@ -2502,7 +2502,7 @@ static unsigned int e1000_update_itr(u16 itr_setting, int packets, int bytes)
retval = lowest_latency;
}
break;
- case bulk_latency: /* 250 usec aka 4000 ints/s */
+ case bulk_latency: /* 250 usec aka 4000 ints/s */
if (bytes > 25000) {
if (packets > 35)
retval = low_latency;
@@ -2554,7 +2554,7 @@ static void e1000_set_itr(struct e1000_adapter *adapter)
new_itr = 70000;
break;
case low_latency:
- new_itr = 20000; /* aka hwitr = ~200 */
+ new_itr = 20000; /* aka hwitr = ~200 */
break;
case bulk_latency:
new_itr = 4000;
@@ -2673,7 +2673,7 @@ static int e1000e_poll(struct napi_struct *napi, int weight)
}
static int e1000_vlan_rx_add_vid(struct net_device *netdev,
- __be16 proto, u16 vid)
+ __always_unused __be16 proto, u16 vid)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -2699,7 +2699,7 @@ static int e1000_vlan_rx_add_vid(struct net_device *netdev,
}
static int e1000_vlan_rx_kill_vid(struct net_device *netdev,
- __be16 proto, u16 vid)
+ __always_unused __be16 proto, u16 vid)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
@@ -3104,13 +3104,13 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
/* UPE and MPE will be handled by normal PROMISC logic
* in e1000e_set_rx_mode
*/
- rctl |= (E1000_RCTL_SBP | /* Receive bad packets */
- E1000_RCTL_BAM | /* RX All Bcast Pkts */
- E1000_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
+ rctl |= (E1000_RCTL_SBP | /* Receive bad packets */
+ E1000_RCTL_BAM | /* RX All Bcast Pkts */
+ E1000_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
- rctl &= ~(E1000_RCTL_VFE | /* Disable VLAN filter */
- E1000_RCTL_DPF | /* Allow filtered pause */
- E1000_RCTL_CFIEN); /* Dis VLAN CFIEN Filter */
+ rctl &= ~(E1000_RCTL_VFE | /* Disable VLAN filter */
+ E1000_RCTL_DPF | /* Allow filtered pause */
+ E1000_RCTL_CFIEN); /* Dis VLAN CFIEN Filter */
/* Do not mess with E1000_CTRL_VME, it affects transmit as well,
* and that breaks VLANs.
*/
@@ -3799,7 +3799,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
hwm = min(((pba << 10) * 9 / 10),
((pba << 10) - adapter->max_frame_size));
- fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
+ fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
fc->low_water = fc->high_water - 8;
break;
case e1000_pchlan:
@@ -3808,10 +3808,10 @@ void e1000e_reset(struct e1000_adapter *adapter)
*/
if (adapter->netdev->mtu > ETH_DATA_LEN) {
fc->high_water = 0x3500;
- fc->low_water = 0x1500;
+ fc->low_water = 0x1500;
} else {
fc->high_water = 0x5000;
- fc->low_water = 0x3000;
+ fc->low_water = 0x3000;
}
fc->refresh_time = 0x1000;
break;
@@ -4581,7 +4581,7 @@ static void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->stats.crcerrs += er32(CRCERRS);
adapter->stats.gprc += er32(GPRC);
adapter->stats.gorc += er32(GORCL);
- er32(GORCH); /* Clear gorc */
+ er32(GORCH); /* Clear gorc */
adapter->stats.bprc += er32(BPRC);
adapter->stats.mprc += er32(MPRC);
adapter->stats.roc += er32(ROC);
@@ -4614,7 +4614,7 @@ static void e1000e_update_stats(struct e1000_adapter *adapter)
adapter->stats.xofftxc += er32(XOFFTXC);
adapter->stats.gptc += er32(GPTC);
adapter->stats.gotc += er32(GOTCL);
- er32(GOTCH); /* Clear gotc */
+ er32(GOTCH); /* Clear gotc */
adapter->stats.rnbc += er32(RNBC);
adapter->stats.ruc += er32(RUC);
@@ -5106,13 +5106,13 @@ static int e1000_tso(struct e1000_ring *tx_ring, struct sk_buff *skb)
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
buffer_info = &tx_ring->buffer_info[i];
- context_desc->lower_setup.ip_fields.ipcss = ipcss;
- context_desc->lower_setup.ip_fields.ipcso = ipcso;
- context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse);
+ context_desc->lower_setup.ip_fields.ipcss = ipcss;
+ context_desc->lower_setup.ip_fields.ipcso = ipcso;
+ context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse);
context_desc->upper_setup.tcp_fields.tucss = tucss;
context_desc->upper_setup.tcp_fields.tucso = tucso;
context_desc->upper_setup.tcp_fields.tucse = 0;
- context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
+ context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss);
context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
context_desc->cmd_and_length = cpu_to_le32(cmd_length);
@@ -5363,7 +5363,7 @@ static void e1000_tx_queue(struct e1000_ring *tx_ring, int tx_flags, int count)
static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter,
struct sk_buff *skb)
{
- struct e1000_hw *hw = &adapter->hw;
+ struct e1000_hw *hw = &adapter->hw;
u16 length, offset;
if (vlan_tx_tag_present(skb) &&
@@ -6259,7 +6259,7 @@ static void e1000_netpoll(struct net_device *netdev)
e1000_intr_msi(adapter->pdev->irq, netdev);
enable_irq(adapter->pdev->irq);
break;
- default: /* E1000E_INT_MODE_LEGACY */
+ default: /* E1000E_INT_MODE_LEGACY */
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev);
enable_irq(adapter->pdev->irq);
@@ -6589,9 +6589,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->eee_advert = MDIO_EEE_100TX | MDIO_EEE_1000T;
/* construct the net_device struct */
- netdev->netdev_ops = &e1000e_netdev_ops;
+ netdev->netdev_ops = &e1000e_netdev_ops;
e1000e_set_ethtool_ops(netdev);
- netdev->watchdog_timeo = 5 * HZ;
+ netdev->watchdog_timeo = 5 * HZ;
netif_napi_add(netdev, &adapter->napi, e1000e_poll, 64);
strlcpy(netdev->name, pci_name(pdev), sizeof(netdev->name));
@@ -7034,7 +7034,6 @@ static void __exit e1000_exit_module(void)
}
module_exit(e1000_exit_module);
-
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c
index 44ddc0a..d70a039 100644
--- a/drivers/net/ethernet/intel/e1000e/nvm.c
+++ b/drivers/net/ethernet/intel/e1000e/nvm.c
@@ -117,7 +117,6 @@ static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
u16 data;
eecd = er32(EECD);
-
eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
data = 0;
diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c
index 59c76a6..da2be59 100644
--- a/drivers/net/ethernet/intel/e1000e/phy.c
+++ b/drivers/net/ethernet/intel/e1000e/phy.c
@@ -1583,13 +1583,13 @@ s32 e1000e_check_downshift(struct e1000_hw *hw)
case e1000_phy_gg82563:
case e1000_phy_bm:
case e1000_phy_82578:
- offset = M88E1000_PHY_SPEC_STATUS;
- mask = M88E1000_PSSR_DOWNSHIFT;
+ offset = M88E1000_PHY_SPEC_STATUS;
+ mask = M88E1000_PSSR_DOWNSHIFT;
break;
case e1000_phy_igp_2:
case e1000_phy_igp_3:
- offset = IGP01E1000_PHY_LINK_HEALTH;
- mask = IGP01E1000_PLHR_SS_DOWNGRADE;
+ offset = IGP01E1000_PHY_LINK_HEALTH;
+ mask = IGP01E1000_PLHR_SS_DOWNGRADE;
break;
default:
/* speed downshift not supported */
@@ -1653,14 +1653,14 @@ s32 e1000_check_polarity_igp(struct e1000_hw *hw)
if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
- offset = IGP01E1000_PHY_PCS_INIT_REG;
- mask = IGP01E1000_PHY_POLARITY_MASK;
+ offset = IGP01E1000_PHY_PCS_INIT_REG;
+ mask = IGP01E1000_PHY_POLARITY_MASK;
} else {
/* This really only applies to 10Mbps since
* there is no polarity for 100Mbps (always 0).
*/
- offset = IGP01E1000_PHY_PORT_STATUS;
- mask = IGP01E1000_PSSR_POLARITY_REVERSED;
+ offset = IGP01E1000_PHY_PORT_STATUS;
+ mask = IGP01E1000_PSSR_POLARITY_REVERSED;
}
ret_val = e1e_rphy(hw, offset, &data);
@@ -1900,7 +1900,7 @@ s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
{
struct e1000_phy_info *phy = &hw->phy;
- s32 ret_val;
+ s32 ret_val;
u16 phy_data;
bool link;
@@ -2253,7 +2253,7 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
case M88E1011_I_PHY_ID:
phy_type = e1000_phy_m88;
break;
- case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+ case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
phy_type = e1000_phy_igp_2;
break;
case GG82563_E_PHY_ID:
@@ -2317,7 +2317,7 @@ s32 e1000e_determine_phy_address(struct e1000_hw *hw)
/* If phy_type is valid, break - we found our
* PHY address
*/
- if (phy_type != e1000_phy_unknown)
+ if (phy_type != e1000_phy_unknown)
return 0;
usleep_range(1000, 2000);
diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c
index ff6a17c..f21a91a 100644
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -401,12 +401,82 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
return 0;
}
+/**
+ * igb_set_sfp_media_type_82575 - derives SFP module media type.
+ * @hw: pointer to the HW structure
+ *
+ * The media type is chosen based on SFP module.
+ * compatibility flags retrieved from SFP ID EEPROM.
+ **/
+static s32 igb_set_sfp_media_type_82575(struct e1000_hw *hw)
+{
+ s32 ret_val = E1000_ERR_CONFIG;
+ u32 ctrl_ext = 0;
+ struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+ struct e1000_sfp_flags *eth_flags = &dev_spec->eth_flags;
+ u8 tranceiver_type = 0;
+ s32 timeout = 3;
+
+ /* Turn I2C interface ON and power on sfp cage */
+ ctrl_ext = rd32(E1000_CTRL_EXT);
+ ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA;
+ wr32(E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_I2C_ENA);
+
+ wrfl();
+
+ /* Read SFP module data */
+ while (timeout) {
+ ret_val = igb_read_sfp_data_byte(hw,
+ E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_IDENTIFIER_OFFSET),
+ &tranceiver_type);
+ if (ret_val == 0)
+ break;
+ msleep(100);
+ timeout--;
+ }
+ if (ret_val != 0)
+ goto out;
+
+ ret_val = igb_read_sfp_data_byte(hw,
+ E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_ETH_FLAGS_OFFSET),
+ (u8 *)eth_flags);
+ if (ret_val != 0)
+ goto out;
+
+ /* Check if there is some SFP module plugged and powered */
+ if ((tranceiver_type == E1000_SFF_IDENTIFIER_SFP) ||
+ (tranceiver_type == E1000_SFF_IDENTIFIER_SFF)) {
+ dev_spec->module_plugged = true;
+ if (eth_flags->e1000_base_lx || eth_flags->e1000_base_sx) {
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+ } else if (eth_flags->e100_base_fx) {
+ dev_spec->sgmii_active = true;
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+ } else if (eth_flags->e1000_base_t) {
+ dev_spec->sgmii_active = true;
+ hw->phy.media_type = e1000_media_type_copper;
+ } else {
+ hw->phy.media_type = e1000_media_type_unknown;
+ hw_dbg("PHY module has not been recognized\n");
+ goto out;
+ }
+ } else {
+ hw->phy.media_type = e1000_media_type_unknown;
+ }
+ ret_val = 0;
+out:
+ /* Restore I2C interface setting */
+ wr32(E1000_CTRL_EXT, ctrl_ext);
+ return ret_val;
+}
+
static s32 igb_get_invariants_82575(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
struct e1000_dev_spec_82575 * dev_spec = &hw->dev_spec._82575;
s32 ret_val;
u32 ctrl_ext = 0;
+ u32 link_mode = 0;
switch (hw->device_id) {
case E1000_DEV_ID_82575EB_COPPER:
@@ -470,16 +540,56 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
*/
hw->phy.media_type = e1000_media_type_copper;
dev_spec->sgmii_active = false;
+ dev_spec->module_plugged = false;
ctrl_ext = rd32(E1000_CTRL_EXT);
- switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
- case E1000_CTRL_EXT_LINK_MODE_SGMII:
- dev_spec->sgmii_active = true;
- break;
+
+ link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK;
+ switch (link_mode) {
case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
- case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
hw->phy.media_type = e1000_media_type_internal_serdes;
break;
+ case E1000_CTRL_EXT_LINK_MODE_SGMII:
+ /* Get phy control interface type set (MDIO vs. I2C)*/
+ if (igb_sgmii_uses_mdio_82575(hw)) {
+ hw->phy.media_type = e1000_media_type_copper;
+ dev_spec->sgmii_active = true;
+ break;
+ }
+ /* fall through for I2C based SGMII */
+ case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
+ /* read media type from SFP EEPROM */
+ ret_val = igb_set_sfp_media_type_82575(hw);
+ if ((ret_val != 0) ||
+ (hw->phy.media_type == e1000_media_type_unknown)) {
+ /* If media type was not identified then return media
+ * type defined by the CTRL_EXT settings.
+ */
+ hw->phy.media_type = e1000_media_type_internal_serdes;
+
+ if (link_mode == E1000_CTRL_EXT_LINK_MODE_SGMII) {
+ hw->phy.media_type = e1000_media_type_copper;
+ dev_spec->sgmii_active = true;
+ }
+
+ break;
+ }
+
+ /* do not change link mode for 100BaseFX */
+ if (dev_spec->eth_flags.e100_base_fx)
+ break;
+
+ /* change current link mode setting */
+ ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
+
+ if (hw->phy.media_type == e1000_media_type_copper)
+ ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_SGMII;
+ else
+ ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
+
+ wr32(E1000_CTRL_EXT, ctrl_ext);
+
+ break;
default:
break;
}
diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h
index 31a0f82..aa201ab 100644
--- a/drivers/net/ethernet/intel/igb/e1000_defines.h
+++ b/drivers/net/ethernet/intel/igb/e1000_defines.h
@@ -61,20 +61,22 @@
/* Clear Interrupt timers after IMS clear */
/* packet buffer parity error detection enabled */
/* descriptor FIFO parity error detection enable */
-#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
-#define E1000_I2CCMD_REG_ADDR_SHIFT 16
-#define E1000_I2CCMD_PHY_ADDR_SHIFT 24
-#define E1000_I2CCMD_OPCODE_READ 0x08000000
-#define E1000_I2CCMD_OPCODE_WRITE 0x00000000
-#define E1000_I2CCMD_READY 0x20000000
-#define E1000_I2CCMD_ERROR 0x80000000
-#define E1000_MAX_SGMII_PHY_REG_ADDR 255
-#define E1000_I2CCMD_PHY_TIMEOUT 200
-#define E1000_IVAR_VALID 0x80
-#define E1000_GPIE_NSICR 0x00000001
-#define E1000_GPIE_MSIX_MODE 0x00000010
-#define E1000_GPIE_EIAME 0x40000000
-#define E1000_GPIE_PBA 0x80000000
+#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
+#define E1000_I2CCMD_REG_ADDR_SHIFT 16
+#define E1000_I2CCMD_PHY_ADDR_SHIFT 24
+#define E1000_I2CCMD_OPCODE_READ 0x08000000
+#define E1000_I2CCMD_OPCODE_WRITE 0x00000000
+#define E1000_I2CCMD_READY 0x20000000
+#define E1000_I2CCMD_ERROR 0x80000000
+#define E1000_I2CCMD_SFP_DATA_ADDR(a) (0x0000 + (a))
+#define E1000_I2CCMD_SFP_DIAG_ADDR(a) (0x0100 + (a))
+#define E1000_MAX_SGMII_PHY_REG_ADDR 255
+#define E1000_I2CCMD_PHY_TIMEOUT 200
+#define E1000_IVAR_VALID 0x80
+#define E1000_GPIE_NSICR 0x00000001
+#define E1000_GPIE_MSIX_MODE 0x00000010
+#define E1000_GPIE_EIAME 0x40000000
+#define E1000_GPIE_PBA 0x80000000
/* Receive Descriptor bit definitions */
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
@@ -270,8 +272,10 @@
#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX
/* LED Control */
-#define E1000_LEDCTL_LED0_MODE_SHIFT 0
-#define E1000_LEDCTL_LED0_BLINK 0x00000080
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_BLINK 0x00000080
+#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
+#define E1000_LEDCTL_LED0_IVRT 0x00000040
#define E1000_LEDCTL_MODE_LED_ON 0xE
#define E1000_LEDCTL_MODE_LED_OFF 0xF
diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h
index 488abb2..94d7866 100644
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
@@ -528,6 +528,8 @@ struct e1000_dev_spec_82575 {
bool global_device_reset;
bool eee_disable;
bool clear_semaphore_once;
+ struct e1000_sfp_flags eth_flags;
+ bool module_plugged;
};
struct e1000_hw {
diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h
index bfc08e0..5caa332 100644
--- a/drivers/net/ethernet/intel/igb/e1000_i210.h
+++ b/drivers/net/ethernet/intel/igb/e1000_i210.h
@@ -82,11 +82,11 @@ enum E1000_INVM_STRUCTURE_TYPE {
#define E1000_INVM_MAJOR_SHIFT 4
#define ID_LED_DEFAULT_I210 ((ID_LED_OFF1_ON2 << 8) | \
- (ID_LED_OFF1_OFF2 << 4) | \
- (ID_LED_DEF1_DEF2))
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_OFF1_OFF2))
#define ID_LED_DEFAULT_I210_SERDES ((ID_LED_DEF1_DEF2 << 8) | \
(ID_LED_DEF1_DEF2 << 4) | \
- (ID_LED_DEF1_DEF2))
+ (ID_LED_OFF1_ON2))
/* NVM offset defaults for i211 device */
#define NVM_INIT_CTRL_2_DEFAULT_I211 0X7243
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c
index 2559d70..bab556a 100644
--- a/drivers/net/ethernet/intel/igb/e1000_mac.c
+++ b/drivers/net/ethernet/intel/igb/e1000_mac.c
@@ -1332,7 +1332,13 @@ s32 igb_id_led_init(struct e1000_hw *hw)
u16 data, i, temp;
const u16 led_mask = 0x0F;
- ret_val = igb_valid_led_default(hw, &data);
+ /* i210 and i211 devices have different LED mechanism */
+ if ((hw->mac.type == e1000_i210) ||
+ (hw->mac.type == e1000_i211))
+ ret_val = igb_valid_led_default_i210(hw, &data);
+ else
+ ret_val = igb_valid_led_default(hw, &data);
+
if (ret_val)
goto out;
@@ -1406,15 +1412,34 @@ s32 igb_blink_led(struct e1000_hw *hw)
u32 ledctl_blink = 0;
u32 i;
- /* set the blink bit for each LED that's "on" (0x0E)
- * in ledctl_mode2
- */
- ledctl_blink = hw->mac.ledctl_mode2;
- for (i = 0; i < 4; i++)
- if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
- E1000_LEDCTL_MODE_LED_ON)
- ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
- (i * 8));
+ if (hw->phy.media_type == e1000_media_type_fiber) {
+ /* always blink LED0 for PCI-E fiber */
+ ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+ } else {
+ /* Set the blink bit for each LED that's "on" (0x0E)
+ * (or "off" if inverted) in ledctl_mode2. The blink
+ * logic in hardware only works when mode is set to "on"
+ * so it must be changed accordingly when the mode is
+ * "off" and inverted.
+ */
+ ledctl_blink = hw->mac.ledctl_mode2;
+ for (i = 0; i < 32; i += 8) {
+ u32 mode = (hw->mac.ledctl_mode2 >> i) &
+ E1000_LEDCTL_LED0_MODE_MASK;
+ u32 led_default = hw->mac.ledctl_default >> i;
+
+ if ((!(led_default & E1000_LEDCTL_LED0_IVRT) &&
+ (mode == E1000_LEDCTL_MODE_LED_ON)) ||
+ ((led_default & E1000_LEDCTL_LED0_IVRT) &&
+ (mode == E1000_LEDCTL_MODE_LED_OFF))) {
+ ledctl_blink &=
+ ~(E1000_LEDCTL_LED0_MODE_MASK << i);
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK |
+ E1000_LEDCTL_MODE_LED_ON) << i;
+ }
+ }
+ }
wr32(E1000_LEDCTL, ledctl_blink);
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c
index 115b0da..1d6a401 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -341,6 +341,130 @@ s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data)
}
/**
+ * igb_read_sfp_data_byte - Reads SFP module data.
+ * @hw: pointer to the HW structure
+ * @offset: byte location offset to be read
+ * @data: read data buffer pointer
+ *
+ * Reads one byte from SFP module data stored
+ * in SFP resided EEPROM memory or SFP diagnostic area.
+ * Function should be called with
+ * E1000_I2CCMD_SFP_DATA_ADDR(<byte offset>) for SFP module database access
+ * E1000_I2CCMD_SFP_DIAG_ADDR(<byte offset>) for SFP diagnostics parameters
+ * access
+ **/
+s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data)
+{
+ u32 i = 0;
+ u32 i2ccmd = 0;
+ u32 data_local = 0;
+
+ if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) {
+ hw_dbg("I2CCMD command address exceeds upper limit\n");
+ return -E1000_ERR_PHY;
+ }
+
+ /* Set up Op-code, EEPROM Address,in the I2CCMD
+ * register. The MAC will take care of interfacing with the
+ * EEPROM to retrieve the desired data.
+ */
+ i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+ E1000_I2CCMD_OPCODE_READ);
+
+ wr32(E1000_I2CCMD, i2ccmd);
+
+ /* Poll the ready bit to see if the I2C read completed */
+ for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+ udelay(50);
+ data_local = rd32(E1000_I2CCMD);
+ if (data_local & E1000_I2CCMD_READY)
+ break;
+ }
+ if (!(data_local & E1000_I2CCMD_READY)) {
+ hw_dbg("I2CCMD Read did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (data_local & E1000_I2CCMD_ERROR) {
+ hw_dbg("I2CCMD Error bit set\n");
+ return -E1000_ERR_PHY;
+ }
+ *data = (u8) data_local & 0xFF;
+
+ return 0;
+}
+
+/**
+ * e1000_write_sfp_data_byte - Writes SFP module data.
+ * @hw: pointer to the HW structure
+ * @offset: byte location offset to write to
+ * @data: data to write
+ *
+ * Writes one byte to SFP module data stored
+ * in SFP resided EEPROM memory or SFP diagnostic area.
+ * Function should be called with
+ * E1000_I2CCMD_SFP_DATA_ADDR(<byte offset>) for SFP module database access
+ * E1000_I2CCMD_SFP_DIAG_ADDR(<byte offset>) for SFP diagnostics parameters
+ * access
+ **/
+s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data)
+{
+ u32 i = 0;
+ u32 i2ccmd = 0;
+ u32 data_local = 0;
+
+ if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) {
+ hw_dbg("I2CCMD command address exceeds upper limit\n");
+ return -E1000_ERR_PHY;
+ }
+ /* The programming interface is 16 bits wide
+ * so we need to read the whole word first
+ * then update appropriate byte lane and write
+ * the updated word back.
+ */
+ /* Set up Op-code, EEPROM Address,in the I2CCMD
+ * register. The MAC will take care of interfacing
+ * with an EEPROM to write the data given.
+ */
+ i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
+ E1000_I2CCMD_OPCODE_READ);
+ /* Set a command to read single word */
+ wr32(E1000_I2CCMD, i2ccmd);
+ for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
+ udelay(50);
+ /* Poll the ready bit to see if lastly
+ * launched I2C operation completed
+ */
+ i2ccmd = rd32(E1000_I2CCMD);
+ if (i2ccmd & E1000_I2CCMD_READY) {
+ /* Check if this is READ or WRITE phase */
+ if ((i2ccmd & E1000_I2CCMD_OPCODE_READ) ==
+ E1000_I2CCMD_OPCODE_READ) {
+ /* Write the selected byte
+ * lane and update whole word
+ */
+ data_local = i2ccmd & 0xFF00;
+ data_local |= data;
+ i2ccmd = ((offset <<
+ E1000_I2CCMD_REG_ADDR_SHIFT) |
+ E1000_I2CCMD_OPCODE_WRITE | data_local);
+ wr32(E1000_I2CCMD, i2ccmd);
+ } else {
+ break;
+ }
+ }
+ }
+ if (!(i2ccmd & E1000_I2CCMD_READY)) {
+ hw_dbg("I2CCMD Write did not complete\n");
+ return -E1000_ERR_PHY;
+ }
+ if (i2ccmd & E1000_I2CCMD_ERROR) {
+ hw_dbg("I2CCMD Error bit set\n");
+ return -E1000_ERR_PHY;
+ }
+ return 0;
+}
+
+/**
* igb_read_phy_reg_igp - Read igp PHY register
* @hw: pointer to the HW structure
* @offset: register offset to be read
diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h
index 784fd1c..6a0873f 100644
--- a/drivers/net/ethernet/intel/igb/e1000_phy.h
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h
@@ -69,6 +69,8 @@ s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
+s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data);
+s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data);
s32 igb_copper_link_setup_82580(struct e1000_hw *hw);
s32 igb_get_phy_info_82580(struct e1000_hw *hw);
s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw);
@@ -157,4 +159,22 @@ s32 igb_check_polarity_m88(struct e1000_hw *hw);
#define GS40G_CS_POWER_DOWN 0x0002
#define GS40G_LINE_LB 0x4000
+/* SFP modules ID memory locations */
+#define E1000_SFF_IDENTIFIER_OFFSET 0x00
+#define E1000_SFF_IDENTIFIER_SFF 0x02
+#define E1000_SFF_IDENTIFIER_SFP 0x03
+
+#define E1000_SFF_ETH_FLAGS_OFFSET 0x06
+/* Flags for SFP modules compatible with ETH up to 1Gb */
+struct e1000_sfp_flags {
+ u8 e1000_base_sx:1;
+ u8 e1000_base_lx:1;
+ u8 e1000_base_cx:1;
+ u8 e1000_base_t:1;
+ u8 e100_base_lx:1;
+ u8 e100_base_fx:1;
+ u8 e10_base_bx10:1;
+ u8 e10_base_px:1;
+};
+
#endif
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 9d6c075..15ea8dc 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -322,11 +322,6 @@ static inline int igb_desc_unused(struct igb_ring *ring)
return ring->count + ring->next_to_clean - ring->next_to_use - 1;
}
-struct igb_i2c_client_list {
- struct i2c_client *client;
- struct igb_i2c_client_list *next;
-};
-
#ifdef CONFIG_IGB_HWMON
#define IGB_HWMON_TYPE_LOC 0
@@ -514,13 +509,18 @@ extern void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
extern void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector,
unsigned char *va,
struct sk_buff *skb);
-static inline void igb_ptp_rx_hwtstamp(struct igb_q_vector *q_vector,
+static inline void igb_ptp_rx_hwtstamp(struct igb_ring *rx_ring,
union e1000_adv_rx_desc *rx_desc,
struct sk_buff *skb)
{
if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TS) &&
!igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP))
- igb_ptp_rx_rgtstamp(q_vector, skb);
+ igb_ptp_rx_rgtstamp(rx_ring->q_vector, skb);
+
+ /* Update the last_rx_timestamp timer in order to enable watchdog check
+ * for error case of latched timestamp on a dropped packet.
+ */
+ rx_ring->last_rx_timestamp = jiffies;
}
extern int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 7876240..85fe7b5 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -142,6 +142,8 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
+ struct e1000_sfp_flags *eth_flags = &dev_spec->eth_flags;
u32 status;
if (hw->phy.media_type == e1000_media_type_copper) {
@@ -162,49 +164,26 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->advertising |= hw->phy.autoneg_advertised;
}
- if (hw->mac.autoneg != 1)
- ecmd->advertising &= ~(ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
-
- if (hw->fc.requested_mode == e1000_fc_full)
- ecmd->advertising |= ADVERTISED_Pause;
- else if (hw->fc.requested_mode == e1000_fc_rx_pause)
- ecmd->advertising |= (ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
- else if (hw->fc.requested_mode == e1000_fc_tx_pause)
- ecmd->advertising |= ADVERTISED_Asym_Pause;
- else
- ecmd->advertising &= ~(ADVERTISED_Pause |
- ADVERTISED_Asym_Pause);
-
ecmd->port = PORT_TP;
ecmd->phy_address = hw->phy.addr;
ecmd->transceiver = XCVR_INTERNAL;
} else {
- ecmd->supported = (SUPPORTED_1000baseT_Full |
- SUPPORTED_100baseT_Full |
- SUPPORTED_FIBRE |
+ ecmd->supported = (SUPPORTED_FIBRE |
SUPPORTED_Autoneg |
SUPPORTED_Pause);
- if (hw->mac.type == e1000_i354)
- ecmd->supported |= SUPPORTED_2500baseX_Full;
-
ecmd->advertising = ADVERTISED_FIBRE;
-
- switch (adapter->link_speed) {
- case SPEED_2500:
- ecmd->advertising = ADVERTISED_2500baseX_Full;
- break;
- case SPEED_1000:
- ecmd->advertising = ADVERTISED_1000baseT_Full;
- break;
- case SPEED_100:
- ecmd->advertising = ADVERTISED_100baseT_Full;
- break;
- default:
- break;
+ if (hw->mac.type == e1000_i354) {
+ ecmd->supported |= SUPPORTED_2500baseX_Full;
+ ecmd->advertising |= ADVERTISED_2500baseX_Full;
+ }
+ if ((eth_flags->e1000_base_lx) || (eth_flags->e1000_base_sx)) {
+ ecmd->supported |= SUPPORTED_1000baseT_Full;
+ ecmd->advertising |= ADVERTISED_1000baseT_Full;
+ }
+ if (eth_flags->e100_base_fx) {
+ ecmd->supported |= SUPPORTED_100baseT_Full;
+ ecmd->advertising |= ADVERTISED_100baseT_Full;
}
-
if (hw->mac.autoneg == 1)
ecmd->advertising |= ADVERTISED_Autoneg;
@@ -212,6 +191,21 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->transceiver = XCVR_EXTERNAL;
}
+ if (hw->mac.autoneg != 1)
+ ecmd->advertising &= ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+
+ if (hw->fc.requested_mode == e1000_fc_full)
+ ecmd->advertising |= ADVERTISED_Pause;
+ else if (hw->fc.requested_mode == e1000_fc_rx_pause)
+ ecmd->advertising |= (ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+ else if (hw->fc.requested_mode == e1000_fc_tx_pause)
+ ecmd->advertising |= ADVERTISED_Asym_Pause;
+ else
+ ecmd->advertising &= ~(ADVERTISED_Pause |
+ ADVERTISED_Asym_Pause);
+
status = rd32(E1000_STATUS);
if (status & E1000_STATUS_LU) {
@@ -392,6 +386,10 @@ static int igb_set_pauseparam(struct net_device *netdev,
struct e1000_hw *hw = &adapter->hw;
int retval = 0;
+ /* 100basefx does not support setting link flow control */
+ if (hw->dev_spec._82575.eth_flags.e100_base_fx)
+ return -EINVAL;
+
adapter->fc_autoneg = pause->autoneg;
while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
@@ -813,10 +811,8 @@ static int igb_set_eeprom(struct net_device *netdev,
ret_val = hw->nvm.ops.write(hw, first_word,
last_word - first_word + 1, eeprom_buff);
- /* Update the checksum over the first part of the EEPROM if needed
- * and flush shadow RAM for 82573 controllers
- */
- if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG)))
+ /* Update the checksum if nvm write succeeded */
+ if (ret_val == 0)
hw->nvm.ops.update(hw);
igb_set_fw_version(adapter);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 64cbe0d..6a0c1b6 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1667,10 +1667,13 @@ void igb_down(struct igb_adapter *adapter)
wrfl();
msleep(10);
- for (i = 0; i < adapter->num_q_vectors; i++)
+ igb_irq_disable(adapter);
+
+ for (i = 0; i < adapter->num_q_vectors; i++) {
+ napi_synchronize(&(adapter->q_vector[i]->napi));
napi_disable(&(adapter->q_vector[i]->napi));
+ }
- igb_irq_disable(adapter);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
@@ -6622,7 +6625,7 @@ static void igb_process_skb_fields(struct igb_ring *rx_ring,
igb_rx_checksum(rx_ring, rx_desc, skb);
- igb_ptp_rx_hwtstamp(rx_ring->q_vector, rx_desc, skb);
+ igb_ptp_rx_hwtstamp(rx_ring, rx_desc, skb);
if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
igb_test_staterr(rx_desc, E1000_RXD_STAT_VP)) {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index ca93238..fb098b4 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -52,6 +52,11 @@
#include <linux/dca.h>
#endif
+#include <net/ll_poll.h>
+
+#ifdef CONFIG_NET_LL_RX_POLL
+#define LL_EXTENDED_STATS
+#endif
/* common prefix used by pr_<> macros */
#undef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -182,6 +187,11 @@ struct ixgbe_rx_buffer {
struct ixgbe_queue_stats {
u64 packets;
u64 bytes;
+#ifdef LL_EXTENDED_STATS
+ u64 yields;
+ u64 misses;
+ u64 cleaned;
+#endif /* LL_EXTENDED_STATS */
};
struct ixgbe_tx_queue_stats {
@@ -356,9 +366,133 @@ struct ixgbe_q_vector {
struct rcu_head rcu; /* to avoid race with update stats on free */
char name[IFNAMSIZ + 9];
+#ifdef CONFIG_NET_LL_RX_POLL
+ unsigned int state;
+#define IXGBE_QV_STATE_IDLE 0
+#define IXGBE_QV_STATE_NAPI 1 /* NAPI owns this QV */
+#define IXGBE_QV_STATE_POLL 2 /* poll owns this QV */
+#define IXGBE_QV_LOCKED (IXGBE_QV_STATE_NAPI | IXGBE_QV_STATE_POLL)
+#define IXGBE_QV_STATE_NAPI_YIELD 4 /* NAPI yielded this QV */
+#define IXGBE_QV_STATE_POLL_YIELD 8 /* poll yielded this QV */
+#define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD)
+#define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD)
+ spinlock_t lock;
+#endif /* CONFIG_NET_LL_RX_POLL */
+
/* for dynamic allocation of rings associated with this q_vector */
struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp;
};
+#ifdef CONFIG_NET_LL_RX_POLL
+static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
+{
+
+ spin_lock_init(&q_vector->lock);
+ q_vector->state = IXGBE_QV_STATE_IDLE;
+}
+
+/* called from the device poll routine to get ownership of a q_vector */
+static inline bool ixgbe_qv_lock_napi(struct ixgbe_q_vector *q_vector)
+{
+ int rc = true;
+ spin_lock(&q_vector->lock);
+ if (q_vector->state & IXGBE_QV_LOCKED) {
+ WARN_ON(q_vector->state & IXGBE_QV_STATE_NAPI);
+ q_vector->state |= IXGBE_QV_STATE_NAPI_YIELD;
+ rc = false;
+#ifdef LL_EXTENDED_STATS
+ q_vector->tx.ring->stats.yields++;
+#endif
+ } else
+ /* we don't care if someone yielded */
+ q_vector->state = IXGBE_QV_STATE_NAPI;
+ spin_unlock(&q_vector->lock);
+ return rc;
+}
+
+/* returns true is someone tried to get the qv while napi had it */
+static inline bool ixgbe_qv_unlock_napi(struct ixgbe_q_vector *q_vector)
+{
+ int rc = false;
+ spin_lock(&q_vector->lock);
+ WARN_ON(q_vector->state & (IXGBE_QV_STATE_POLL |
+ IXGBE_QV_STATE_NAPI_YIELD));
+
+ if (q_vector->state & IXGBE_QV_STATE_POLL_YIELD)
+ rc = true;
+ q_vector->state = IXGBE_QV_STATE_IDLE;
+ spin_unlock(&q_vector->lock);
+ return rc;
+}
+
+/* called from ixgbe_low_latency_poll() */
+static inline bool ixgbe_qv_lock_poll(struct ixgbe_q_vector *q_vector)
+{
+ int rc = true;
+ spin_lock_bh(&q_vector->lock);
+ if ((q_vector->state & IXGBE_QV_LOCKED)) {
+ q_vector->state |= IXGBE_QV_STATE_POLL_YIELD;
+ rc = false;
+#ifdef LL_EXTENDED_STATS
+ q_vector->rx.ring->stats.yields++;
+#endif
+ } else
+ /* preserve yield marks */
+ q_vector->state |= IXGBE_QV_STATE_POLL;
+ spin_unlock_bh(&q_vector->lock);
+ return rc;
+}
+
+/* returns true if someone tried to get the qv while it was locked */
+static inline bool ixgbe_qv_unlock_poll(struct ixgbe_q_vector *q_vector)
+{
+ int rc = false;
+ spin_lock_bh(&q_vector->lock);
+ WARN_ON(q_vector->state & (IXGBE_QV_STATE_NAPI));
+
+ if (q_vector->state & IXGBE_QV_STATE_POLL_YIELD)
+ rc = true;
+ q_vector->state = IXGBE_QV_STATE_IDLE;
+ spin_unlock_bh(&q_vector->lock);
+ return rc;
+}
+
+/* true if a socket is polling, even if it did not get the lock */
+static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
+{
+ WARN_ON(!(q_vector->state & IXGBE_QV_LOCKED));
+ return q_vector->state & IXGBE_QV_USER_PEND;
+}
+#else /* CONFIG_NET_LL_RX_POLL */
+static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
+{
+}
+
+static inline bool ixgbe_qv_lock_napi(struct ixgbe_q_vector *q_vector)
+{
+ return true;
+}
+
+static inline bool ixgbe_qv_unlock_napi(struct ixgbe_q_vector *q_vector)
+{
+ return false;
+}
+
+static inline bool ixgbe_qv_lock_poll(struct ixgbe_q_vector *q_vector)
+{
+ return false;
+}
+
+static inline bool ixgbe_qv_unlock_poll(struct ixgbe_q_vector *q_vector)
+{
+ return false;
+}
+
+static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
+{
+ return false;
+}
+#endif /* CONFIG_NET_LL_RX_POLL */
+
#ifdef CONFIG_IXGBE_HWMON
#define IXGBE_HWMON_TYPE_LOC 0
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
index 1f2c805..e055e00 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c
@@ -380,3 +380,26 @@ s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw,
}
return 0;
}
+
+static void ixgbe_dcb_read_rtrup2tc_82599(struct ixgbe_hw *hw, u8 *map)
+{
+ u32 reg, i;
+
+ reg = IXGBE_READ_REG(hw, IXGBE_RTRUP2TC);
+ for (i = 0; i < MAX_USER_PRIORITY; i++)
+ map[i] = IXGBE_RTRUP2TC_UP_MASK &
+ (reg >> (i * IXGBE_RTRUP2TC_UP_SHIFT));
+ return;
+}
+
+void ixgbe_dcb_read_rtrup2tc(struct ixgbe_hw *hw, u8 *map)
+{
+ switch (hw->mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
+ ixgbe_dcb_read_rtrup2tc_82599(hw, map);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
index 1634de8..fc0a2dd 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h
@@ -159,6 +159,8 @@ s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, u16 *refill, u16 *max,
s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en, u8 *tc_prio);
s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *);
+void ixgbe_dcb_read_rtrup2tc(struct ixgbe_hw *hw, u8 *map);
+
/* DCB definitions for credit calculation */
#define DCB_CREDIT_QUANTUM 64 /* DCB Quantum */
#define MAX_CREDIT_REFILL 511 /* 0x1FF * 64B = 32704B */
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
index a4ef076..d71d9ce 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
@@ -45,6 +45,7 @@
/* Receive UP2TC mapping */
#define IXGBE_RTRUP2TC_UP_SHIFT 3
+#define IXGBE_RTRUP2TC_UP_MASK 7
/* Transmit UP2TC mapping */
#define IXGBE_RTTUP2TC_UP_SHIFT 3
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
index f3d68f9..edd89a1 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c
@@ -554,6 +554,9 @@ static int ixgbe_dcbnl_ieee_setets(struct net_device *dev,
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
adapter->ixgbe_ieee_ets->prio_tc[i] =
IEEE_8021QAZ_MAX_TCS;
+ /* if possible update UP2TC mappings from HW */
+ ixgbe_dcb_read_rtrup2tc(&adapter->hw,
+ adapter->ixgbe_ieee_ets->prio_tc);
}
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index d375472..24e2e7a 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1054,6 +1054,12 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
data[i] = 0;
data[i+1] = 0;
i += 2;
+#ifdef LL_EXTENDED_STATS
+ data[i] = 0;
+ data[i+1] = 0;
+ data[i+2] = 0;
+ i += 3;
+#endif
continue;
}
@@ -1063,6 +1069,12 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
data[i+1] = ring->stats.bytes;
} while (u64_stats_fetch_retry_bh(&ring->syncp, start));
i += 2;
+#ifdef LL_EXTENDED_STATS
+ data[i] = ring->stats.yields;
+ data[i+1] = ring->stats.misses;
+ data[i+2] = ring->stats.cleaned;
+ i += 3;
+#endif
}
for (j = 0; j < IXGBE_NUM_RX_QUEUES; j++) {
ring = adapter->rx_ring[j];
@@ -1070,6 +1082,12 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
data[i] = 0;
data[i+1] = 0;
i += 2;
+#ifdef LL_EXTENDED_STATS
+ data[i] = 0;
+ data[i+1] = 0;
+ data[i+2] = 0;
+ i += 3;
+#endif
continue;
}
@@ -1079,6 +1097,12 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
data[i+1] = ring->stats.bytes;
} while (u64_stats_fetch_retry_bh(&ring->syncp, start));
i += 2;
+#ifdef LL_EXTENDED_STATS
+ data[i] = ring->stats.yields;
+ data[i+1] = ring->stats.misses;
+ data[i+2] = ring->stats.cleaned;
+ i += 3;
+#endif
}
for (j = 0; j < IXGBE_MAX_PACKET_BUFFERS; j++) {
@@ -1115,12 +1139,28 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
p += ETH_GSTRING_LEN;
sprintf(p, "tx_queue_%u_bytes", i);
p += ETH_GSTRING_LEN;
+#ifdef LL_EXTENDED_STATS
+ sprintf(p, "tx_q_%u_napi_yield", i);
+ p += ETH_GSTRING_LEN;
+ sprintf(p, "tx_q_%u_misses", i);
+ p += ETH_GSTRING_LEN;
+ sprintf(p, "tx_q_%u_cleaned", i);
+ p += ETH_GSTRING_LEN;
+#endif /* LL_EXTENDED_STATS */
}
for (i = 0; i < IXGBE_NUM_RX_QUEUES; i++) {
sprintf(p, "rx_queue_%u_packets", i);
p += ETH_GSTRING_LEN;
sprintf(p, "rx_queue_%u_bytes", i);
p += ETH_GSTRING_LEN;
+#ifdef LL_EXTENDED_STATS
+ sprintf(p, "rx_q_%u_ll_poll_yield", i);
+ p += ETH_GSTRING_LEN;
+ sprintf(p, "rx_q_%u_misses", i);
+ p += ETH_GSTRING_LEN;
+ sprintf(p, "rx_q_%u_cleaned", i);
+ p += ETH_GSTRING_LEN;
+#endif /* LL_EXTENDED_STATS */
}
for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) {
sprintf(p, "tx_pb_%u_pxon", i);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
index ef5f7a6..90b4e10 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
@@ -811,6 +811,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter,
/* initialize NAPI */
netif_napi_add(adapter->netdev, &q_vector->napi,
ixgbe_poll, 64);
+ napi_hash_add(&q_vector->napi);
/* tie q_vector and adapter together */
adapter->q_vector[v_idx] = q_vector;
@@ -931,6 +932,7 @@ static void ixgbe_free_q_vector(struct ixgbe_adapter *adapter, int v_idx)
adapter->rx_ring[ring->queue_index] = NULL;
adapter->q_vector[v_idx] = NULL;
+ napi_hash_del(&q_vector->napi);
netif_napi_del(&q_vector->napi);
/*
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index d30fbdd..047ebaa 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -1504,7 +1504,9 @@ static void ixgbe_rx_skb(struct ixgbe_q_vector *q_vector,
{
struct ixgbe_adapter *adapter = q_vector->adapter;
- if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
+ if (ixgbe_qv_ll_polling(q_vector))
+ netif_receive_skb(skb);
+ else if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
napi_gro_receive(&q_vector->napi, skb);
else
netif_rx(skb);
@@ -1892,9 +1894,9 @@ dma_sync:
* expensive overhead for IOMMU access this provides a means of avoiding
* it by maintaining the mapping of the page to the syste.
*
- * Returns true if all work is completed without reaching budget
+ * Returns amount of work completed
**/
-static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
+static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
struct ixgbe_ring *rx_ring,
const int budget)
{
@@ -1976,6 +1978,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
}
#endif /* IXGBE_FCOE */
+ skb_mark_ll(skb, &q_vector->napi);
ixgbe_rx_skb(q_vector, skb);
/* update budget accounting */
@@ -1992,9 +1995,43 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
if (cleaned_count)
ixgbe_alloc_rx_buffers(rx_ring, cleaned_count);
- return (total_rx_packets < budget);
+ return total_rx_packets;
}
+#ifdef CONFIG_NET_LL_RX_POLL
+/* must be called with local_bh_disable()d */
+static int ixgbe_low_latency_recv(struct napi_struct *napi)
+{
+ struct ixgbe_q_vector *q_vector =
+ container_of(napi, struct ixgbe_q_vector, napi);
+ struct ixgbe_adapter *adapter = q_vector->adapter;
+ struct ixgbe_ring *ring;
+ int found = 0;
+
+ if (test_bit(__IXGBE_DOWN, &adapter->state))
+ return LL_FLUSH_FAILED;
+
+ if (!ixgbe_qv_lock_poll(q_vector))
+ return LL_FLUSH_BUSY;
+
+ ixgbe_for_each_ring(ring, q_vector->rx) {
+ found = ixgbe_clean_rx_irq(q_vector, ring, 4);
+#ifdef LL_EXTENDED_STATS
+ if (found)
+ ring->stats.cleaned += found;
+ else
+ ring->stats.misses++;
+#endif
+ if (found)
+ break;
+ }
+
+ ixgbe_qv_unlock_poll(q_vector);
+
+ return found;
+}
+#endif /* CONFIG_NET_LL_RX_POLL */
+
/**
* ixgbe_configure_msix - Configure MSI-X hardware
* @adapter: board private structure
@@ -2550,6 +2587,9 @@ int ixgbe_poll(struct napi_struct *napi, int budget)
ixgbe_for_each_ring(ring, q_vector->tx)
clean_complete &= !!ixgbe_clean_tx_irq(q_vector, ring);
+ if (!ixgbe_qv_lock_napi(q_vector))
+ return budget;
+
/* attempt to distribute budget to each queue fairly, but don't allow
* the budget to go below 1 because we'll exit polling */
if (q_vector->rx.count > 1)
@@ -2558,9 +2598,10 @@ int ixgbe_poll(struct napi_struct *napi, int budget)
per_ring_budget = budget;
ixgbe_for_each_ring(ring, q_vector->rx)
- clean_complete &= ixgbe_clean_rx_irq(q_vector, ring,
- per_ring_budget);
+ clean_complete &= (ixgbe_clean_rx_irq(q_vector, ring,
+ per_ring_budget) < per_ring_budget);
+ ixgbe_qv_unlock_napi(q_vector);
/* If all work not completed, return budget and keep polling */
if (!clean_complete)
return budget;
@@ -3747,16 +3788,25 @@ static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
{
int q_idx;
- for (q_idx = 0; q_idx < adapter->num_q_vectors; q_idx++)
+ for (q_idx = 0; q_idx < adapter->num_q_vectors; q_idx++) {
+ ixgbe_qv_init_lock(adapter->q_vector[q_idx]);
napi_enable(&adapter->q_vector[q_idx]->napi);
+ }
}
static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter)
{
int q_idx;
- for (q_idx = 0; q_idx < adapter->num_q_vectors; q_idx++)
+ local_bh_disable(); /* for ixgbe_qv_lock_napi() */
+ for (q_idx = 0; q_idx < adapter->num_q_vectors; q_idx++) {
napi_disable(&adapter->q_vector[q_idx]->napi);
+ while (!ixgbe_qv_lock_napi(adapter->q_vector[q_idx])) {
+ pr_info("QV %d locked\n", q_idx);
+ mdelay(1);
+ }
+ }
+ local_bh_enable();
}
#ifdef CONFIG_IXGBE_DCB
@@ -7177,6 +7227,9 @@ static const struct net_device_ops ixgbe_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ixgbe_netpoll,
#endif
+#ifdef CONFIG_NET_LL_RX_POLL
+ .ndo_ll_poll = ixgbe_low_latency_recv,
+#endif
#ifdef IXGBE_FCOE
.ndo_fcoe_ddp_setup = ixgbe_fcoe_ddp_get,
.ndo_fcoe_ddp_target = ixgbe_fcoe_ddp_target,
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index 070a6f1..7fbe6ab 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -3148,7 +3148,6 @@ jme_init_one(struct pci_dev *pdev,
jme->mii_if.mdio_write = jme_mdio_write;
jme_clear_pm(jme);
- pci_set_power_state(jme->pdev, PCI_D0);
device_set_wakeup_enable(&pdev->dev, true);
jme_set_phyfifo_5level(jme);
diff --git a/drivers/net/ethernet/korina.c b/drivers/net/ethernet/korina.c
index 5409fe8..64646eb 100644
--- a/drivers/net/ethernet/korina.c
+++ b/drivers/net/ethernet/korina.c
@@ -495,12 +495,9 @@ static void korina_multicast_list(struct net_device *dev)
/* Build the hash table */
if (netdev_mc_count(dev) > 4) {
- u16 hash_table[4];
+ u16 hash_table[4] = { 0 };
u32 crc;
- for (i = 0; i < 4; i++)
- hash_table[i] = 0;
-
netdev_for_each_mc_addr(ha, dev) {
crc = ether_crc_le(6, ha->addr);
crc >>= 26;
@@ -1214,7 +1211,6 @@ static int korina_remove(struct platform_device *pdev)
iounmap(lp->rx_dma_regs);
iounmap(lp->tx_dma_regs);
- platform_set_drvdata(pdev, NULL);
unregister_netdev(bif->dev);
free_netdev(bif->dev);
diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
index d0afeea..510d506 100644
--- a/drivers/net/ethernet/marvell/mv643xx_eth.c
+++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
@@ -60,6 +60,10 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
static char mv643xx_eth_driver_name[] = "mv643xx_eth";
static char mv643xx_eth_driver_version[] = "1.4";
@@ -115,6 +119,8 @@ static char mv643xx_eth_driver_version[] = "1.4";
#define LINK_UP 0x00000002
#define TXQ_COMMAND 0x0048
#define TXQ_FIX_PRIO_CONF 0x004c
+#define PORT_SERIAL_CONTROL1 0x004c
+#define CLK125_BYPASS_EN 0x00000010
#define TX_BW_RATE 0x0050
#define TX_BW_MTU 0x0058
#define TX_BW_BURST 0x005c
@@ -615,7 +621,7 @@ static int rxq_refill(struct rx_queue *rxq, int budget)
rx_desc = rxq->rx_desc_area + rx;
- size = skb->end - skb->data;
+ size = skb_end_pointer(skb) - skb->data;
rx_desc->buf_ptr = dma_map_single(mp->dev->dev.parent,
skb->data, size,
DMA_FROM_DEVICE);
@@ -867,7 +873,7 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
struct netdev_queue *nq = netdev_get_tx_queue(mp->dev, txq->index);
int reclaimed;
- __netif_tx_lock(nq, smp_processor_id());
+ __netif_tx_lock_bh(nq);
reclaimed = 0;
while (reclaimed < budget && txq->tx_desc_count > 0) {
@@ -913,7 +919,7 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
dev_kfree_skb(skb);
}
- __netif_tx_unlock(nq);
+ __netif_tx_unlock_bh(nq);
if (reclaimed < budget)
mp->work_tx &= ~(1 << txq->index);
@@ -2450,13 +2456,150 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp)
}
}
+#if defined(CONFIG_OF)
+static const struct of_device_id mv643xx_eth_shared_ids[] = {
+ { .compatible = "marvell,orion-eth", },
+ { .compatible = "marvell,kirkwood-eth", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids);
+#endif
+
+#if defined(CONFIG_OF) && !defined(CONFIG_MV64X60)
+#define mv643xx_eth_property(_np, _name, _v) \
+ do { \
+ u32 tmp; \
+ if (!of_property_read_u32(_np, "marvell," _name, &tmp)) \
+ _v = tmp; \
+ } while (0)
+
+static struct platform_device *port_platdev[3];
+
+static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
+ struct device_node *pnp)
+{
+ struct platform_device *ppdev;
+ struct mv643xx_eth_platform_data ppd;
+ struct resource res;
+ const char *mac_addr;
+ int ret;
+
+ memset(&ppd, 0, sizeof(ppd));
+ ppd.shared = pdev;
+
+ memset(&res, 0, sizeof(res));
+ if (!of_irq_to_resource(pnp, 0, &res)) {
+ dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name);
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(pnp, "reg", &ppd.port_number)) {
+ dev_err(&pdev->dev, "missing reg property on %s\n", pnp->name);
+ return -EINVAL;
+ }
+
+ if (ppd.port_number >= 3) {
+ dev_err(&pdev->dev, "invalid reg property on %s\n", pnp->name);
+ return -EINVAL;
+ }
+
+ mac_addr = of_get_mac_address(pnp);
+ if (mac_addr)
+ memcpy(ppd.mac_addr, mac_addr, 6);
+
+ mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size);
+ mv643xx_eth_property(pnp, "tx-sram-addr", ppd.tx_sram_addr);
+ mv643xx_eth_property(pnp, "tx-sram-size", ppd.tx_sram_size);
+ mv643xx_eth_property(pnp, "rx-queue-size", ppd.rx_queue_size);
+ mv643xx_eth_property(pnp, "rx-sram-addr", ppd.rx_sram_addr);
+ mv643xx_eth_property(pnp, "rx-sram-size", ppd.rx_sram_size);
+
+ ppd.phy_node = of_parse_phandle(pnp, "phy-handle", 0);
+ if (!ppd.phy_node) {
+ ppd.phy_addr = MV643XX_ETH_PHY_NONE;
+ of_property_read_u32(pnp, "speed", &ppd.speed);
+ of_property_read_u32(pnp, "duplex", &ppd.duplex);
+ }
+
+ ppdev = platform_device_alloc(MV643XX_ETH_NAME, ppd.port_number);
+ if (!ppdev)
+ return -ENOMEM;
+ ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = platform_device_add_resources(ppdev, &res, 1);
+ if (ret)
+ goto port_err;
+
+ ret = platform_device_add_data(ppdev, &ppd, sizeof(ppd));
+ if (ret)
+ goto port_err;
+
+ ret = platform_device_add(ppdev);
+ if (ret)
+ goto port_err;
+
+ port_platdev[ppd.port_number] = ppdev;
+
+ return 0;
+
+port_err:
+ platform_device_put(ppdev);
+ return ret;
+}
+
+static int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
+{
+ struct mv643xx_eth_shared_platform_data *pd;
+ struct device_node *pnp, *np = pdev->dev.of_node;
+ int ret;
+
+ /* bail out if not registered from DT */
+ if (!np)
+ return 0;
+
+ pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+ pdev->dev.platform_data = pd;
+
+ mv643xx_eth_property(np, "tx-checksum-limit", pd->tx_csum_limit);
+
+ for_each_available_child_of_node(np, pnp) {
+ ret = mv643xx_eth_shared_of_add_port(pdev, pnp);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static void mv643xx_eth_shared_of_remove(void)
+{
+ int n;
+
+ for (n = 0; n < 3; n++) {
+ platform_device_del(port_platdev[n]);
+ port_platdev[n] = NULL;
+ }
+}
+#else
+static inline int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static inline void mv643xx_eth_shared_of_remove(void)
+{
+}
+#endif
+
static int mv643xx_eth_shared_probe(struct platform_device *pdev)
{
static int mv643xx_eth_version_printed;
- struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
+ struct mv643xx_eth_shared_platform_data *pd;
struct mv643xx_eth_shared_private *msp;
const struct mbus_dram_target_info *dram;
struct resource *res;
+ int ret;
if (!mv643xx_eth_version_printed++)
pr_notice("MV-643xx 10/100/1000 ethernet driver version %s\n",
@@ -2469,8 +2612,9 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
msp = devm_kzalloc(&pdev->dev, sizeof(*msp), GFP_KERNEL);
if (msp == NULL)
return -ENOMEM;
+ platform_set_drvdata(pdev, msp);
- msp->base = ioremap(res->start, resource_size(res));
+ msp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (msp->base == NULL)
return -ENOMEM;
@@ -2485,12 +2629,15 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
if (dram)
mv643xx_eth_conf_mbus_windows(msp, dram);
+ ret = mv643xx_eth_shared_of_probe(pdev);
+ if (ret)
+ return ret;
+ pd = pdev->dev.platform_data;
+
msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
pd->tx_csum_limit : 9 * 1024;
infer_hw_params(msp);
- platform_set_drvdata(pdev, msp);
-
return 0;
}
@@ -2498,10 +2645,9 @@ static int mv643xx_eth_shared_remove(struct platform_device *pdev)
{
struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev);
- iounmap(msp->base);
+ mv643xx_eth_shared_of_remove();
if (!IS_ERR(msp->clk))
clk_disable_unprepare(msp->clk);
-
return 0;
}
@@ -2511,6 +2657,7 @@ static struct platform_driver mv643xx_eth_shared_driver = {
.driver = {
.name = MV643XX_ETH_SHARED_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mv643xx_eth_shared_ids),
},
};
@@ -2701,6 +2848,15 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
mp->dev = dev;
+ /* Kirkwood resets some registers on gated clocks. Especially
+ * CLK125_BYPASS_EN must be cleared but is not available on
+ * all other SoCs/System Controllers using this driver.
+ */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "marvell,kirkwood-eth-port"))
+ wrlp(mp, PORT_SERIAL_CONTROL1,
+ rdlp(mp, PORT_SERIAL_CONTROL1) & ~CLK125_BYPASS_EN);
+
/*
* Start with a default rate, and if there is a clock, allow
* it to override the default.
@@ -2710,23 +2866,35 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
if (!IS_ERR(mp->clk)) {
clk_prepare_enable(mp->clk);
mp->t_clk = clk_get_rate(mp->clk);
+ } else if (!IS_ERR(mp->shared->clk)) {
+ mp->t_clk = clk_get_rate(mp->shared->clk);
}
set_params(mp, pd);
netif_set_real_num_tx_queues(dev, mp->txq_count);
netif_set_real_num_rx_queues(dev, mp->rxq_count);
- if (pd->phy_addr != MV643XX_ETH_PHY_NONE) {
+ err = 0;
+ if (pd->phy_node) {
+ mp->phy = of_phy_connect(mp->dev, pd->phy_node,
+ mv643xx_eth_adjust_link, 0,
+ PHY_INTERFACE_MODE_GMII);
+ if (!mp->phy)
+ err = -ENODEV;
+ } else if (pd->phy_addr != MV643XX_ETH_PHY_NONE) {
mp->phy = phy_scan(mp, pd->phy_addr);
- if (IS_ERR(mp->phy)) {
+ if (IS_ERR(mp->phy))
err = PTR_ERR(mp->phy);
- if (err == -ENODEV)
- err = -EPROBE_DEFER;
- goto out;
- }
- phy_init(mp, pd->speed, pd->duplex);
+ else
+ phy_init(mp, pd->speed, pd->duplex);
}
+ if (err == -ENODEV) {
+ err = -EPROBE_DEFER;
+ goto out;
+ }
+ if (err)
+ goto out;
SET_ETHTOOL_OPS(dev, &mv643xx_eth_ethtool_ops);
@@ -2745,7 +2913,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
INIT_WORK(&mp->tx_timeout_task, tx_timeout_task);
- netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 128);
+ netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, NAPI_POLL_WEIGHT);
init_timer(&mp->rx_oom);
mp->rx_oom.data = (unsigned long)mp;
@@ -2805,7 +2973,7 @@ static int mv643xx_eth_remove(struct platform_device *pdev)
unregister_netdev(mp->dev);
if (mp->phy != NULL)
- phy_detach(mp->phy);
+ phy_disconnect(mp->phy);
cancel_work_sync(&mp->tx_timeout_task);
if (!IS_ERR(mp->clk))
@@ -2813,8 +2981,6 @@ static int mv643xx_eth_remove(struct platform_device *pdev)
free_netdev(mp->dev);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index c966785..712779f 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -2251,6 +2251,21 @@ static int mvneta_change_mtu(struct net_device *dev, int mtu)
return 0;
}
+/* Get mac address */
+static void mvneta_get_mac_addr(struct mvneta_port *pp, unsigned char *addr)
+{
+ u32 mac_addr_l, mac_addr_h;
+
+ mac_addr_l = mvreg_read(pp, MVNETA_MAC_ADDR_LOW);
+ mac_addr_h = mvreg_read(pp, MVNETA_MAC_ADDR_HIGH);
+ addr[0] = (mac_addr_h >> 24) & 0xFF;
+ addr[1] = (mac_addr_h >> 16) & 0xFF;
+ addr[2] = (mac_addr_h >> 8) & 0xFF;
+ addr[3] = mac_addr_h & 0xFF;
+ addr[4] = (mac_addr_l >> 8) & 0xFF;
+ addr[5] = mac_addr_l & 0xFF;
+}
+
/* Handle setting mac address */
static int mvneta_set_mac_addr(struct net_device *dev, void *addr)
{
@@ -2667,7 +2682,9 @@ static int mvneta_probe(struct platform_device *pdev)
u32 phy_addr;
struct mvneta_port *pp;
struct net_device *dev;
- const char *mac_addr;
+ const char *dt_mac_addr;
+ char hw_mac_addr[ETH_ALEN];
+ const char *mac_from;
int phy_mode;
int err;
@@ -2703,13 +2720,6 @@ static int mvneta_probe(struct platform_device *pdev)
goto err_free_irq;
}
- mac_addr = of_get_mac_address(dn);
-
- if (!mac_addr || !is_valid_ether_addr(mac_addr))
- eth_hw_addr_random(dev);
- else
- memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
-
dev->tx_queue_len = MVNETA_MAX_TXD;
dev->watchdog_timeo = 5 * HZ;
dev->netdev_ops = &mvneta_netdev_ops;
@@ -2740,6 +2750,21 @@ static int mvneta_probe(struct platform_device *pdev)
clk_prepare_enable(pp->clk);
+ dt_mac_addr = of_get_mac_address(dn);
+ if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) {
+ mac_from = "device tree";
+ memcpy(dev->dev_addr, dt_mac_addr, ETH_ALEN);
+ } else {
+ mvneta_get_mac_addr(pp, hw_mac_addr);
+ if (is_valid_ether_addr(hw_mac_addr)) {
+ mac_from = "hardware";
+ memcpy(dev->dev_addr, hw_mac_addr, ETH_ALEN);
+ } else {
+ mac_from = "random";
+ eth_hw_addr_random(dev);
+ }
+ }
+
pp->tx_done_timer.data = (unsigned long)dev;
pp->tx_ring_size = MVNETA_MAX_TXD;
@@ -2772,7 +2797,8 @@ static int mvneta_probe(struct platform_device *pdev)
goto err_deinit;
}
- netdev_info(dev, "mac: %pM\n", dev->dev_addr);
+ netdev_info(dev, "Using %s mac address %pM\n", mac_from,
+ dev->dev_addr);
platform_set_drvdata(pdev, pp->dev);
@@ -2804,8 +2830,6 @@ static int mvneta_remove(struct platform_device *pdev)
irq_dispose_mapping(dev->irq);
free_netdev(dev);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/net/ethernet/marvell/pxa168_eth.c b/drivers/net/ethernet/marvell/pxa168_eth.c
index 339bb32..ec20508 100644
--- a/drivers/net/ethernet/marvell/pxa168_eth.c
+++ b/drivers/net/ethernet/marvell/pxa168_eth.c
@@ -357,7 +357,7 @@ static void rxq_refill(struct net_device *dev)
/* Get 'used' Rx descriptor */
used_rx_desc = pep->rx_used_desc_q;
p_used_rx_desc = &pep->p_rx_desc_area[used_rx_desc];
- size = skb->end - skb->data;
+ size = skb_end_pointer(skb) - skb->data;
p_used_rx_desc->buf_ptr = dma_map_single(NULL,
skb->data,
size,
@@ -1602,7 +1602,6 @@ static int pxa168_eth_remove(struct platform_device *pdev)
unregister_netdev(dev);
cancel_work_sync(&pep->tx_timeout_task);
free_netdev(dev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c
index 171f4b3..c896079 100644
--- a/drivers/net/ethernet/marvell/skge.c
+++ b/drivers/net/ethernet/marvell/skge.c
@@ -3706,7 +3706,7 @@ static const struct file_operations skge_debug_fops = {
static int skge_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct skge_port *skge;
struct dentry *d;
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index d175bbd..e09a8c6 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -4642,7 +4642,7 @@ static const struct file_operations sky2_debug_fops = {
static int sky2_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct sky2_port *sky2 = netdev_priv(dev);
if (dev->netdev_ops->ndo_open != sky2_open || !sky2_debug)
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 1df56cc..ea1e038 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -39,6 +39,7 @@
#include <linux/errno.h>
#include <linux/mlx4/cmd.h>
+#include <linux/mlx4/device.h>
#include <linux/semaphore.h>
#include <rdma/ib_smi.h>
@@ -222,8 +223,6 @@ static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param,
* FLR process. The only non-zero result in the RESET command
* is MLX4_DELAY_RESET_SLAVE*/
if ((MLX4_COMM_CMD_RESET == cmd)) {
- mlx4_warn(dev, "Got slave FLRed from Communication"
- " channel (ret:0x%x)\n", ret_from_pending);
err = MLX4_DELAY_RESET_SLAVE;
} else {
mlx4_warn(dev, "Communication channel timed out\n");
@@ -2180,7 +2179,54 @@ int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_in
ivf->qos = s_info->default_qos;
ivf->tx_rate = s_info->tx_rate;
ivf->spoofchk = s_info->spoofchk;
+ ivf->linkstate = s_info->link_state;
return 0;
}
EXPORT_SYMBOL_GPL(mlx4_get_vf_config);
+
+int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_vport_state *s_info;
+ struct mlx4_vport_oper_state *vp_oper;
+ int slave;
+ u8 link_stat_event;
+
+ slave = mlx4_get_slave_indx(dev, vf);
+ if (slave < 0)
+ return -EINVAL;
+
+ switch (link_state) {
+ case IFLA_VF_LINK_STATE_AUTO:
+ /* get current link state */
+ if (!priv->sense.do_sense_port[port])
+ link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE;
+ else
+ link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN;
+ break;
+
+ case IFLA_VF_LINK_STATE_ENABLE:
+ link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_ACTIVE;
+ break;
+
+ case IFLA_VF_LINK_STATE_DISABLE:
+ link_stat_event = MLX4_PORT_CHANGE_SUBTYPE_DOWN;
+ break;
+
+ default:
+ mlx4_warn(dev, "unknown value for link_state %02x on slave %d port %d\n",
+ link_state, slave, port);
+ return -EINVAL;
+ };
+ /* update the admin & oper state on the link state */
+ s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
+ vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+ s_info->link_state = link_state;
+ vp_oper->state.link_state = link_state;
+
+ /* send event */
+ mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_set_vf_link_state);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index 1e6c594..3e2d504 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
@@ -139,6 +139,7 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq,
if (!cq->is_tx) {
netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64);
+ napi_hash_add(&cq->napi);
napi_enable(&cq->napi);
}
@@ -162,6 +163,8 @@ void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
{
if (!cq->is_tx) {
napi_disable(&cq->napi);
+ napi_hash_del(&cq->napi);
+ synchronize_rcu();
netif_napi_del(&cq->napi);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index c9e6b62..727874f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -222,7 +222,12 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
switch (sset) {
case ETH_SS_STATS:
return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) +
- (priv->tx_ring_num + priv->rx_ring_num) * 2;
+ (priv->tx_ring_num * 2) +
+#ifdef CONFIG_NET_LL_RX_POLL
+ (priv->rx_ring_num * 5);
+#else
+ (priv->rx_ring_num * 2);
+#endif
case ETH_SS_TEST:
return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.flags
& MLX4_DEV_CAP_FLAG_UC_LOOPBACK) * 2;
@@ -271,6 +276,11 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
for (i = 0; i < priv->rx_ring_num; i++) {
data[index++] = priv->rx_ring[i].packets;
data[index++] = priv->rx_ring[i].bytes;
+#ifdef CONFIG_NET_LL_RX_POLL
+ data[index++] = priv->rx_ring[i].yields;
+ data[index++] = priv->rx_ring[i].misses;
+ data[index++] = priv->rx_ring[i].cleaned;
+#endif
}
spin_unlock_bh(&priv->stats_lock);
@@ -334,6 +344,14 @@ static void mlx4_en_get_strings(struct net_device *dev,
"rx%d_packets", i);
sprintf(data + (index++) * ETH_GSTRING_LEN,
"rx%d_bytes", i);
+#ifdef CONFIG_NET_LL_RX_POLL
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "rx%d_napi_yield", i);
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "rx%d_misses", i);
+ sprintf(data + (index++) * ETH_GSTRING_LEN,
+ "rx%d_cleaned", i);
+#endif
}
break;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index b35f947..7299ada 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -38,6 +38,7 @@
#include <linux/slab.h>
#include <linux/hash.h>
#include <net/ip.h>
+#include <net/ll_poll.h>
#include <linux/mlx4/driver.h>
#include <linux/mlx4/device.h>
@@ -67,6 +68,34 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up)
return 0;
}
+#ifdef CONFIG_NET_LL_RX_POLL
+/* must be called with local_bh_disable()d */
+static int mlx4_en_low_latency_recv(struct napi_struct *napi)
+{
+ struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi);
+ struct net_device *dev = cq->dev;
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_rx_ring *rx_ring = &priv->rx_ring[cq->ring];
+ int done;
+
+ if (!priv->port_up)
+ return LL_FLUSH_FAILED;
+
+ if (!mlx4_en_cq_lock_poll(cq))
+ return LL_FLUSH_BUSY;
+
+ done = mlx4_en_process_rx_cq(dev, cq, 4);
+ if (likely(done))
+ rx_ring->cleaned += done;
+ else
+ rx_ring->misses++;
+
+ mlx4_en_cq_unlock_poll(cq);
+
+ return done;
+}
+#endif /* CONFIG_NET_LL_RX_POLL */
+
#ifdef CONFIG_RFS_ACCEL
struct mlx4_en_filter {
@@ -1323,6 +1352,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv)
priv->last_moder_time[ring] = moder_time;
cq = &priv->rx_cq[ring];
cq->moder_time = moder_time;
+ cq->moder_cnt = priv->rx_frames;
err = mlx4_en_set_cq_moder(priv, cq);
if (err)
en_err(priv, "Failed modifying moderation for cq:%d\n",
@@ -1444,6 +1474,8 @@ int mlx4_en_start_port(struct net_device *dev)
for (i = 0; i < priv->rx_ring_num; i++) {
cq = &priv->rx_cq[i];
+ mlx4_en_cq_init_lock(cq);
+
err = mlx4_en_activate_cq(priv, cq, i);
if (err) {
en_err(priv, "Failed activating Rx CQ\n");
@@ -1693,10 +1725,19 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
/* Free RX Rings */
for (i = 0; i < priv->rx_ring_num; i++) {
+ struct mlx4_en_cq *cq = &priv->rx_cq[i];
+
+ local_bh_disable();
+ while (!mlx4_en_cq_lock_napi(cq)) {
+ pr_info("CQ %d locked\n", i);
+ mdelay(1);
+ }
+ local_bh_enable();
+
mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
- while (test_bit(NAPI_STATE_SCHED, &priv->rx_cq[i].napi.state))
+ while (test_bit(NAPI_STATE_SCHED, &cq->napi.state))
msleep(1);
- mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]);
+ mlx4_en_deactivate_cq(priv, cq);
}
/* close port*/
@@ -2060,6 +2101,13 @@ static int mlx4_en_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_
return mlx4_get_vf_config(mdev->dev, en_priv->port, vf, ivf);
}
+static int mlx4_en_set_vf_link_state(struct net_device *dev, int vf, int link_state)
+{
+ struct mlx4_en_priv *en_priv = netdev_priv(dev);
+ struct mlx4_en_dev *mdev = en_priv->mdev;
+
+ return mlx4_set_vf_link_state(mdev->dev, en_priv->port, vf, link_state);
+}
static const struct net_device_ops mlx4_netdev_ops = {
.ndo_open = mlx4_en_open,
.ndo_stop = mlx4_en_close,
@@ -2082,6 +2130,9 @@ static const struct net_device_ops mlx4_netdev_ops = {
#ifdef CONFIG_RFS_ACCEL
.ndo_rx_flow_steer = mlx4_en_filter_rfs,
#endif
+#ifdef CONFIG_NET_LL_RX_POLL
+ .ndo_ll_poll = mlx4_en_low_latency_recv,
+#endif
};
static const struct net_device_ops mlx4_netdev_ops_master = {
@@ -2100,6 +2151,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
.ndo_set_vf_mac = mlx4_en_set_vf_mac,
.ndo_set_vf_vlan = mlx4_en_set_vf_vlan,
.ndo_set_vf_spoofchk = mlx4_en_set_vf_spoofchk,
+ .ndo_set_vf_link_state = mlx4_en_set_vf_link_state,
.ndo_get_vf_config = mlx4_en_get_vf_config,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = mlx4_en_netpoll,
@@ -2118,6 +2170,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
struct mlx4_en_priv *priv;
int i;
int err;
+ u64 mac_u64;
dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv),
MAX_TX_RINGS, MAX_RX_RINGS);
@@ -2191,10 +2244,17 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
dev->addr_len = ETH_ALEN;
mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]);
if (!is_valid_ether_addr(dev->dev_addr)) {
- en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n",
- priv->port, dev->dev_addr);
- err = -EINVAL;
- goto out;
+ if (mlx4_is_slave(priv->mdev->dev)) {
+ eth_hw_addr_random(dev);
+ en_warn(priv, "Assigned random MAC address %pM\n", dev->dev_addr);
+ mac_u64 = mlx4_en_mac_to_u64(dev->dev_addr);
+ mdev->dev->caps.def_mac[priv->port] = mac_u64;
+ } else {
+ en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n",
+ priv->port, dev->dev_addr);
+ err = -EINVAL;
+ goto out;
+ }
}
memcpy(priv->prev_mac, dev->dev_addr, sizeof(priv->prev_mac));
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
index 91f2b2c..d3f5086 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
@@ -60,7 +60,7 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
context->pri_path.sched_queue = 0x83 | (priv->port - 1) << 6;
if (user_prio >= 0) {
context->pri_path.sched_queue |= user_prio << 3;
- context->pri_path.feup = 1 << 6;
+ context->pri_path.feup = MLX4_FEUP_FORCE_ETH_UP;
}
context->pri_path.counter_index = 0xff;
context->cqn_send = cpu_to_be32(cqn);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index 02aee1e..9c57581 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -31,6 +31,7 @@
*
*/
+#include <net/ll_poll.h>
#include <linux/mlx4/cq.h>
#include <linux/slab.h>
#include <linux/mlx4/qp.h>
@@ -656,8 +657,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
* - DIX Ethernet (type interpretation)
* - TCP/IP (v4)
* - without IP options
- * - not an IP fragment */
- if (dev->features & NETIF_F_GRO) {
+ * - not an IP fragment
+ * - no LLS polling in progress
+ */
+ if (!mlx4_en_cq_ll_polling(cq) &&
+ (dev->features & NETIF_F_GRO)) {
struct sk_buff *gro_skb = napi_get_frags(&cq->napi);
if (!gro_skb)
goto next;
@@ -737,6 +741,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
timestamp);
}
+ skb_mark_ll(skb, &cq->napi);
+
/* Push it up the stack */
netif_receive_skb(skb);
@@ -781,8 +787,13 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget)
struct mlx4_en_priv *priv = netdev_priv(dev);
int done;
+ if (!mlx4_en_cq_lock_napi(cq))
+ return budget;
+
done = mlx4_en_process_rx_cq(dev, cq, budget);
+ mlx4_en_cq_unlock_napi(cq);
+
/* If we used up all the quota - we're probably not done yet... */
if (done == budget)
INC_PERF_COUNTER(priv->pstats.napi_quota);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index 4e6877a..7c49238 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -544,7 +544,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb)
if (vlan_tx_tag_present(skb))
up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT;
- return __skb_tx_hash(dev, skb, rings_p_up) + up * rings_p_up;
+ return __netdev_pick_tx(dev, skb) % rings_p_up + up * rings_p_up;
}
static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 6000342..7e04286 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -448,6 +448,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
int i;
enum slave_port_gen_event gen_event;
unsigned long flags;
+ struct mlx4_vport_state *s_info;
while ((eqe = next_eqe_sw(eq, dev->caps.eqe_factor))) {
/*
@@ -556,7 +557,9 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
mlx4_dbg(dev, "%s: Sending MLX4_PORT_CHANGE_SUBTYPE_DOWN"
" to slave: %d, port:%d\n",
__func__, i, port);
- mlx4_slave_event(dev, i, eqe);
+ s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
+ if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state)
+ mlx4_slave_event(dev, i, eqe);
} else { /* IB port */
set_and_calc_slave_port_state(dev, i, port,
MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN,
@@ -580,7 +583,9 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
for (i = 0; i < dev->num_slaves; i++) {
if (i == mlx4_master_func_num(dev))
continue;
- mlx4_slave_event(dev, i, eqe);
+ s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
+ if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state)
+ mlx4_slave_event(dev, i, eqe);
}
else /* IB port */
/* port-up event will be sent to a slave when the
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index b147bdd..569bbe3 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -131,7 +131,9 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
[2] = "RSS XOR Hash Function support",
[3] = "Device manage flow steering support",
[4] = "Automatic MAC reassignment support",
- [5] = "Time stamping support"
+ [5] = "Time stamping support",
+ [6] = "VST (control vlan insertion/stripping) support",
+ [7] = "FSM (MAC anti-spoofing) support"
};
int i;
@@ -828,8 +830,10 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
u8 port_type;
u16 short_field;
int err;
+ int admin_link_state;
#define MLX4_VF_PORT_NO_LINK_SENSE_MASK 0xE0
+#define MLX4_PORT_LINK_UP_MASK 0x80
#define QUERY_PORT_CUR_MAX_PKEY_OFFSET 0x0c
#define QUERY_PORT_CUR_MAX_GID_OFFSET 0x0e
@@ -838,12 +842,16 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
MLX4_CMD_NATIVE);
if (!err && dev->caps.function != slave) {
- /* set slave default_mac address */
- MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET);
- def_mac += slave << 8;
/* if config MAC in DB use it */
if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac)
def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
+ else {
+ /* set slave default_mac address */
+ MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET);
+ def_mac += slave << 8;
+ priv->mfunc.master.vf_admin[slave].vport[vhcr->in_modifier].mac = def_mac;
+ }
+
MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
/* get port type - currently only eth is enabled */
@@ -855,6 +863,12 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
/* set port type to currently operating port type */
port_type |= (dev->caps.port_type[vhcr->in_modifier] & 0x3);
+ admin_link_state = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.link_state;
+ if (IFLA_VF_LINK_STATE_ENABLE == admin_link_state)
+ port_type |= MLX4_PORT_LINK_UP_MASK;
+ else if (IFLA_VF_LINK_STATE_DISABLE == admin_link_state)
+ port_type &= ~MLX4_PORT_LINK_UP_MASK;
+
MLX4_PUT(outbox->buf, port_type,
QUERY_PORT_SUPPORTED_TYPE_OFFSET);
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 0d32a82..2f4a260 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -1290,7 +1290,6 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
u64 dma = (u64) priv->mfunc.vhcr_dma;
- int num_of_reset_retries = NUM_OF_RESET_RETRIES;
int ret_from_reset = 0;
u32 slave_read;
u32 cmd_channel_ver;
@@ -1304,18 +1303,10 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
* NUM_OF_RESET_RETRIES times before leaving.*/
if (ret_from_reset) {
if (MLX4_DELAY_RESET_SLAVE == ret_from_reset) {
- msleep(SLEEP_TIME_IN_RESET);
- while (ret_from_reset && num_of_reset_retries) {
- mlx4_warn(dev, "slave is currently in the"
- "middle of FLR. retrying..."
- "(try num:%d)\n",
- (NUM_OF_RESET_RETRIES -
- num_of_reset_retries + 1));
- ret_from_reset =
- mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET,
- 0, MLX4_COMM_TIME);
- num_of_reset_retries = num_of_reset_retries - 1;
- }
+ mlx4_warn(dev, "slave is currently in the "
+ "middle of FLR. Deferring probe.\n");
+ mutex_unlock(&priv->cmd.slave_cmd_mutex);
+ return -EPROBE_DEFER;
} else
goto err;
}
@@ -1526,7 +1517,8 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
} else {
err = mlx4_init_slave(dev);
if (err) {
- mlx4_err(dev, "Failed to initialize slave\n");
+ if (err != -EPROBE_DEFER)
+ mlx4_err(dev, "Failed to initialize slave\n");
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index df15bb6..7527293 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -482,6 +482,7 @@ struct mlx4_vport_state {
u8 default_qos;
u32 tx_rate;
bool spoofchk;
+ u32 link_state;
};
struct mlx4_vf_admin_state {
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index b1d7657..57192a8 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -98,11 +98,11 @@
#define MLX4_EN_ALLOC_SIZE PAGE_ALIGN(16384)
#define MLX4_EN_ALLOC_ORDER get_order(MLX4_EN_ALLOC_SIZE)
-/* Receive fragment sizes; we use at most 4 fragments (for 9600 byte MTU
+/* Receive fragment sizes; we use at most 3 fragments (for 9600 byte MTU
* and 4K allocations) */
enum {
- FRAG_SZ0 = 512 - NET_IP_ALIGN,
- FRAG_SZ1 = 1024,
+ FRAG_SZ0 = 1536 - NET_IP_ALIGN,
+ FRAG_SZ1 = 4096,
FRAG_SZ2 = 4096,
FRAG_SZ3 = MLX4_EN_ALLOC_SIZE
};
@@ -290,6 +290,11 @@ struct mlx4_en_rx_ring {
void *rx_info;
unsigned long bytes;
unsigned long packets;
+#ifdef CONFIG_NET_LL_RX_POLL
+ unsigned long yields;
+ unsigned long misses;
+ unsigned long cleaned;
+#endif
unsigned long csum_ok;
unsigned long csum_none;
int hwtstamp_rx_filter;
@@ -310,6 +315,19 @@ struct mlx4_en_cq {
u16 moder_cnt;
struct mlx4_cqe *buf;
#define MLX4_EN_OPCODE_ERROR 0x1e
+
+#ifdef CONFIG_NET_LL_RX_POLL
+ unsigned int state;
+#define MLX4_EN_CQ_STATE_IDLE 0
+#define MLX4_EN_CQ_STATE_NAPI 1 /* NAPI owns this CQ */
+#define MLX4_EN_CQ_STATE_POLL 2 /* poll owns this CQ */
+#define MLX4_CQ_LOCKED (MLX4_EN_CQ_STATE_NAPI | MLX4_EN_CQ_STATE_POLL)
+#define MLX4_EN_CQ_STATE_NAPI_YIELD 4 /* NAPI yielded this CQ */
+#define MLX4_EN_CQ_STATE_POLL_YIELD 8 /* poll yielded this CQ */
+#define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD)
+#define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
+ spinlock_t poll_lock; /* protects from LLS/napi conflicts */
+#endif /* CONFIG_NET_LL_RX_POLL */
};
struct mlx4_en_port_profile {
@@ -562,6 +580,115 @@ struct mlx4_mac_entry {
struct rcu_head rcu;
};
+#ifdef CONFIG_NET_LL_RX_POLL
+static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
+{
+ spin_lock_init(&cq->poll_lock);
+ cq->state = MLX4_EN_CQ_STATE_IDLE;
+}
+
+/* called from the device poll rutine to get ownership of a cq */
+static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq)
+{
+ int rc = true;
+ spin_lock(&cq->poll_lock);
+ if (cq->state & MLX4_CQ_LOCKED) {
+ WARN_ON(cq->state & MLX4_EN_CQ_STATE_NAPI);
+ cq->state |= MLX4_EN_CQ_STATE_NAPI_YIELD;
+ rc = false;
+ } else
+ /* we don't care if someone yielded */
+ cq->state = MLX4_EN_CQ_STATE_NAPI;
+ spin_unlock(&cq->poll_lock);
+ return rc;
+}
+
+/* returns true is someone tried to get the cq while napi had it */
+static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq)
+{
+ int rc = false;
+ spin_lock(&cq->poll_lock);
+ WARN_ON(cq->state & (MLX4_EN_CQ_STATE_POLL |
+ MLX4_EN_CQ_STATE_NAPI_YIELD));
+
+ if (cq->state & MLX4_EN_CQ_STATE_POLL_YIELD)
+ rc = true;
+ cq->state = MLX4_EN_CQ_STATE_IDLE;
+ spin_unlock(&cq->poll_lock);
+ return rc;
+}
+
+/* called from mlx4_en_low_latency_poll() */
+static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq)
+{
+ int rc = true;
+ spin_lock_bh(&cq->poll_lock);
+ if ((cq->state & MLX4_CQ_LOCKED)) {
+ struct net_device *dev = cq->dev;
+ struct mlx4_en_priv *priv = netdev_priv(dev);
+ struct mlx4_en_rx_ring *rx_ring = &priv->rx_ring[cq->ring];
+
+ cq->state |= MLX4_EN_CQ_STATE_POLL_YIELD;
+ rc = false;
+ rx_ring->yields++;
+ } else
+ /* preserve yield marks */
+ cq->state |= MLX4_EN_CQ_STATE_POLL;
+ spin_unlock_bh(&cq->poll_lock);
+ return rc;
+}
+
+/* returns true if someone tried to get the cq while it was locked */
+static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq)
+{
+ int rc = false;
+ spin_lock_bh(&cq->poll_lock);
+ WARN_ON(cq->state & (MLX4_EN_CQ_STATE_NAPI));
+
+ if (cq->state & MLX4_EN_CQ_STATE_POLL_YIELD)
+ rc = true;
+ cq->state = MLX4_EN_CQ_STATE_IDLE;
+ spin_unlock_bh(&cq->poll_lock);
+ return rc;
+}
+
+/* true if a socket is polling, even if it did not get the lock */
+static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
+{
+ WARN_ON(!(cq->state & MLX4_CQ_LOCKED));
+ return cq->state & CQ_USER_PEND;
+}
+#else
+static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
+{
+}
+
+static inline bool mlx4_en_cq_lock_napi(struct mlx4_en_cq *cq)
+{
+ return true;
+}
+
+static inline bool mlx4_en_cq_unlock_napi(struct mlx4_en_cq *cq)
+{
+ return false;
+}
+
+static inline bool mlx4_en_cq_lock_poll(struct mlx4_en_cq *cq)
+{
+ return false;
+}
+
+static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq)
+{
+ return false;
+}
+
+static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
+{
+ return false;
+}
+#endif /* CONFIG_NET_LL_RX_POLL */
+
#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
void mlx4_en_update_loopback_state(struct net_device *dev,
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index e12e0d2..1157f02 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -372,24 +372,29 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
if (MLX4_QP_ST_RC == qp_type)
return -EINVAL;
+ /* force strip vlan by clear vsd */
+ qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN);
+ if (0 != vp_oper->state.default_vlan) {
+ qpc->pri_path.vlan_control =
+ MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
+ MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
+ MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED;
+ } else { /* priority tagged */
+ qpc->pri_path.vlan_control =
+ MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
+ MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
+ }
+
+ qpc->pri_path.fvl_rx |= MLX4_FVL_RX_FORCE_ETH_VLAN;
qpc->pri_path.vlan_index = vp_oper->vlan_idx;
- qpc->pri_path.fl = (1 << 6) | (1 << 2); /* set cv bit and hide_cqe_vlan bit*/
- qpc->pri_path.feup |= 1 << 3; /* set fvl bit */
+ qpc->pri_path.fl |= MLX4_FL_CV | MLX4_FL_ETH_HIDE_CQE_VLAN;
+ qpc->pri_path.feup |= MLX4_FEUP_FORCE_ETH_UP | MLX4_FVL_FORCE_ETH_VLAN;
qpc->pri_path.sched_queue &= 0xC7;
qpc->pri_path.sched_queue |= (vp_oper->state.default_qos) << 3;
- mlx4_dbg(dev, "qp %d port %d Q 0x%x set vlan to %d vidx %d feup %x fl %x\n",
- be32_to_cpu(qpc->local_qpn) & 0xffffff, port,
- (int)(qpc->pri_path.sched_queue), vp_oper->state.default_vlan,
- vp_oper->vlan_idx, (int)(qpc->pri_path.feup),
- (int)(qpc->pri_path.fl));
}
if (vp_oper->state.spoofchk) {
- qpc->pri_path.feup |= 1 << 5; /* set fsm bit */;
+ qpc->pri_path.feup |= MLX4_FSM_FORCE_ETH_SRC_MAC;
qpc->pri_path.grh_mylmc = (0x80 & qpc->pri_path.grh_mylmc) + vp_oper->mac_idx;
- mlx4_dbg(dev, "spoof qp %d port %d feup 0x%x, myLmc 0x%x mindx %d\n",
- be32_to_cpu(qpc->local_qpn) & 0xffffff, port,
- (int)qpc->pri_path.feup, (int)qpc->pri_path.grh_mylmc,
- vp_oper->mac_idx);
}
return 0;
}
diff --git a/drivers/net/ethernet/micrel/Kconfig b/drivers/net/ethernet/micrel/Kconfig
index fe42fc0..d16b11e 100644
--- a/drivers/net/ethernet/micrel/Kconfig
+++ b/drivers/net/ethernet/micrel/Kconfig
@@ -22,7 +22,6 @@ if NET_VENDOR_MICREL
config ARM_KS8695_ETHER
tristate "KS8695 Ethernet support"
depends on ARM && ARCH_KS8695
- select NET_CORE
select MII
---help---
If you wish to compile a kernel for the KS8695 and want to
@@ -39,7 +38,6 @@ config KS8842
config KS8851
tristate "Micrel KS8851 SPI"
depends on SPI
- select NET_CORE
select MII
select CRC32
select EEPROM_93CX6
@@ -49,7 +47,6 @@ config KS8851
config KS8851_MLL
tristate "Micrel KS8851 MLL"
depends on HAS_IOMEM
- select NET_CORE
select MII
---help---
This platform driver is for Micrel KS8851 Address/data bus
@@ -58,7 +55,6 @@ config KS8851_MLL
config KSZ884X_PCI
tristate "Micrel KSZ8841/2 PCI"
depends on PCI
- select NET_CORE
select MII
select CRC32
---help---
diff --git a/drivers/net/ethernet/micrel/ks8695net.c b/drivers/net/ethernet/micrel/ks8695net.c
index b6c60fd..106eb97 100644
--- a/drivers/net/ethernet/micrel/ks8695net.c
+++ b/drivers/net/ethernet/micrel/ks8695net.c
@@ -1600,7 +1600,6 @@ ks8695_drv_remove(struct platform_device *pdev)
struct net_device *ndev = platform_get_drvdata(pdev);
struct ks8695_priv *ksp = netdev_priv(ndev);
- platform_set_drvdata(pdev, NULL);
netif_napi_del(&ksp->napi);
unregister_netdev(ndev);
diff --git a/drivers/net/ethernet/micrel/ks8842.c b/drivers/net/ethernet/micrel/ks8842.c
index fbcb9e7..e393d99 100644
--- a/drivers/net/ethernet/micrel/ks8842.c
+++ b/drivers/net/ethernet/micrel/ks8842.c
@@ -1250,7 +1250,6 @@ static int ks8842_remove(struct platform_device *pdev)
iounmap(adapter->hw_addr);
free_netdev(netdev);
release_mem_region(iomem->start, resource_size(iomem));
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/ethernet/micrel/ks8851_mll.c b/drivers/net/ethernet/micrel/ks8851_mll.c
index ddaf138..ac20098 100644
--- a/drivers/net/ethernet/micrel/ks8851_mll.c
+++ b/drivers/net/ethernet/micrel/ks8851_mll.c
@@ -35,6 +35,9 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/ks8851_mll.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
#define DRV_NAME "ks8851_mll"
@@ -1524,6 +1527,13 @@ static int ks_hw_init(struct ks_net *ks)
return true;
}
+#if defined(CONFIG_OF)
+static const struct of_device_id ks8851_ml_dt_ids[] = {
+ { .compatible = "micrel,ks8851-mll" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ks8851_ml_dt_ids);
+#endif
static int ks8851_probe(struct platform_device *pdev)
{
@@ -1532,7 +1542,7 @@ static int ks8851_probe(struct platform_device *pdev)
struct net_device *netdev;
struct ks_net *ks;
u16 id, data;
- struct ks8851_mll_platform_data *pdata;
+ const char *mac;
io_d = platform_get_resource(pdev, IORESOURCE_MEM, 0);
io_c = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1619,13 +1629,21 @@ static int ks8851_probe(struct platform_device *pdev)
ks_wrreg16(ks, KS_OBCR, data | OBCR_ODS_16MA);
/* overwriting the default MAC address */
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- netdev_err(netdev, "No platform data\n");
- err = -ENODEV;
- goto err_pdata;
+ if (pdev->dev.of_node) {
+ mac = of_get_mac_address(pdev->dev.of_node);
+ if (mac)
+ memcpy(ks->mac_addr, mac, ETH_ALEN);
+ } else {
+ struct ks8851_mll_platform_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ netdev_err(netdev, "No platform data\n");
+ err = -ENODEV;
+ goto err_pdata;
+ }
+ memcpy(ks->mac_addr, pdata->mac_addr, ETH_ALEN);
}
- memcpy(ks->mac_addr, pdata->mac_addr, 6);
if (!is_valid_ether_addr(ks->mac_addr)) {
/* Use random MAC address if none passed */
eth_random_addr(ks->mac_addr);
@@ -1671,7 +1689,6 @@ static int ks8851_remove(struct platform_device *pdev)
iounmap(ks->hw_addr);
free_netdev(netdev);
release_mem_region(iomem->start, resource_size(iomem));
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -1680,6 +1697,7 @@ static struct platform_driver ks8851_platform_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ks8851_ml_dt_ids),
},
.probe = ks8851_probe,
.remove = ks8851_remove,
diff --git a/drivers/net/ethernet/netx-eth.c b/drivers/net/ethernet/netx-eth.c
index cb9e638..dc2c6f56 100644
--- a/drivers/net/ethernet/netx-eth.c
+++ b/drivers/net/ethernet/netx-eth.c
@@ -422,7 +422,6 @@ exit_free_pfifo:
exit_free_xc:
free_xc(priv->xc);
exit_free_netdev:
- platform_set_drvdata(pdev, NULL);
free_netdev(ndev);
exit:
return ret;
@@ -430,11 +429,9 @@ exit:
static int netx_eth_drv_remove(struct platform_device *pdev)
{
- struct net_device *ndev = dev_get_drvdata(&pdev->dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
struct netx_eth_priv *priv = netdev_priv(ndev);
- platform_set_drvdata(pdev, NULL);
-
unregister_netdev(ndev);
xc_stop(priv->xc);
free_xc(priv->xc);
diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig
index 334c171..01182b5 100644
--- a/drivers/net/ethernet/nuvoton/Kconfig
+++ b/drivers/net/ethernet/nuvoton/Kconfig
@@ -22,7 +22,6 @@ config W90P910_ETH
tristate "Nuvoton w90p910 Ethernet support"
depends on ARM && ARCH_W90X900
select PHYLIB
- select NET_CORE
select MII
---help---
Say Y here if you want to use built-in Ethernet ports
diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c
index 3df8287..e88bdb1 100644
--- a/drivers/net/ethernet/nuvoton/w90p910_ether.c
+++ b/drivers/net/ethernet/nuvoton/w90p910_ether.c
@@ -1051,7 +1051,6 @@ failed_put_clk:
clk_put(ether->clk);
failed_free_rxirq:
free_irq(ether->rxirq, pdev);
- platform_set_drvdata(pdev, NULL);
failed_free_txirq:
free_irq(ether->txirq, pdev);
failed_free_io:
@@ -1080,7 +1079,6 @@ static int w90p910_ether_remove(struct platform_device *pdev)
free_irq(ether->rxirq, dev);
del_timer_sync(&ether->check_timer);
- platform_set_drvdata(pdev, NULL);
free_netdev(dev);
return 0;
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index b003fe5..098b96d 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -6340,7 +6340,7 @@ static DEFINE_PCI_DEVICE_TABLE(pci_tbl) = {
{0,},
};
-static struct pci_driver driver = {
+static struct pci_driver forcedeth_pci_driver = {
.name = DRV_NAME,
.id_table = pci_tbl,
.probe = nv_probe,
@@ -6349,16 +6349,6 @@ static struct pci_driver driver = {
.driver.pm = NV_PM_OPS,
};
-static int __init init_nic(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit exit_nic(void)
-{
- pci_unregister_driver(&driver);
-}
-
module_param(max_interrupt_work, int, 0);
MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt");
module_param(optimization_mode, int, 0);
@@ -6379,11 +6369,8 @@ module_param(debug_tx_timeout, bool, 0);
MODULE_PARM_DESC(debug_tx_timeout,
"Dump tx related registers and ring when tx_timeout happens");
+module_pci_driver(forcedeth_pci_driver);
MODULE_AUTHOR("Manfred Spraul <manfred@colorfullife.com>");
MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver");
MODULE_LICENSE("GPL");
-
MODULE_DEVICE_TABLE(pci, pci_tbl);
-
-module_init(init_nic);
-module_exit(exit_nic);
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index 55a5548..a061b93 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -1483,7 +1483,6 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
return 0;
err_out_unregister_netdev:
- platform_set_drvdata(pdev, NULL);
unregister_netdev(ndev);
err_out_dma_unmap:
if (!use_iram_for_net(&pldat->pdev->dev) ||
@@ -1511,7 +1510,6 @@ static int lpc_eth_drv_remove(struct platform_device *pdev)
struct netdata_local *pldat = netdev_priv(ndev);
unregister_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
if (!use_iram_for_net(&pldat->pdev->dev) ||
pldat->dma_buff_size > lpc32xx_return_iram_size())
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c
index 921729f..e6e0292 100644
--- a/drivers/net/ethernet/octeon/octeon_mgmt.c
+++ b/drivers/net/ethernet/octeon/octeon_mgmt.c
@@ -1437,7 +1437,7 @@ static int octeon_mgmt_probe(struct platform_device *pdev)
SET_NETDEV_DEV(netdev, &pdev->dev);
- dev_set_drvdata(&pdev->dev, netdev);
+ platform_set_drvdata(pdev, netdev);
p = netdev_priv(netdev);
netif_napi_add(netdev, &p->napi, octeon_mgmt_napi_poll,
OCTEON_MGMT_NAPI_WEIGHT);
@@ -1559,7 +1559,7 @@ err:
static int octeon_mgmt_remove(struct platform_device *pdev)
{
- struct net_device *netdev = dev_get_drvdata(&pdev->dev);
+ struct net_device *netdev = platform_get_drvdata(pdev);
unregister_netdev(netdev);
free_netdev(netdev);
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
index 34d05bf..cb22341 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
@@ -5,7 +5,6 @@
config PCH_GBE
tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE"
depends on PCI
- select NET_CORE
select MII
select PTP_1588_CLOCK_PCH
---help---
diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig
index cbbeca3..8d51800 100644
--- a/drivers/net/ethernet/packetengines/Kconfig
+++ b/drivers/net/ethernet/packetengines/Kconfig
@@ -21,7 +21,6 @@ if NET_PACKET_ENGINE
config HAMACHI
tristate "Packet Engines Hamachi GNIC-II support"
depends on PCI
- select NET_CORE
select MII
---help---
If you have a Gigabit Ethernet card of this type, say Y and read
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
index 322a36b..3fe09ab 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic.h
@@ -53,8 +53,8 @@
#define _NETXEN_NIC_LINUX_MAJOR 4
#define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 80
-#define NETXEN_NIC_LINUX_VERSIONID "4.0.80"
+#define _NETXEN_NIC_LINUX_SUBVERSION 81
+#define NETXEN_NIC_LINUX_VERSIONID "4.0.81"
#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -1855,7 +1855,7 @@ static const struct netxen_brdinfo netxen_boards[] = {
#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(netxen_boards)
-static inline void get_brd_name_by_type(u32 type, char *name)
+static inline int netxen_nic_get_brd_name_by_type(u32 type, char *name)
{
int i, found = 0;
for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
@@ -1864,10 +1864,14 @@ static inline void get_brd_name_by_type(u32 type, char *name)
found = 1;
break;
}
+ }
+ if (!found) {
+ strcpy(name, "Unknown");
+ return -EINVAL;
}
- if (!found)
- name = "Unknown";
+
+ return 0;
}
static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring)
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h
index 28e0769..32c7906 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h
@@ -734,6 +734,9 @@ enum {
#define NIC_CRB_BASE_2 (NETXEN_CAM_RAM(0x700))
#define NETXEN_NIC_REG(X) (NIC_CRB_BASE+(X))
#define NETXEN_NIC_REG_2(X) (NIC_CRB_BASE_2+(X))
+#define NETXEN_INTR_MODE_REG NETXEN_NIC_REG(0x44)
+#define NETXEN_MSI_MODE 0x1
+#define NETXEN_INTX_MODE 0x2
#define NX_CDRP_CRB_OFFSET (NETXEN_NIC_REG(0x18))
#define NX_ARG1_CRB_OFFSET (NETXEN_NIC_REG(0x1c))
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index af951f3..c401b0b 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -592,48 +592,60 @@ static const struct net_device_ops netxen_netdev_ops = {
#endif
};
-static void
-netxen_setup_intr(struct netxen_adapter *adapter)
+static inline bool netxen_function_zero(struct pci_dev *pdev)
{
- struct netxen_legacy_intr_set *legacy_intrp;
- struct pci_dev *pdev = adapter->pdev;
- int err, num_msix;
+ return (PCI_FUNC(pdev->devfn) == 0) ? true : false;
+}
- if (adapter->rss_supported) {
- num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
- MSIX_ENTRIES_PER_ADAPTER : 2;
- } else
- num_msix = 1;
+static inline void netxen_set_interrupt_mode(struct netxen_adapter *adapter,
+ u32 mode)
+{
+ NXWR32(adapter, NETXEN_INTR_MODE_REG, mode);
+}
- adapter->max_sds_rings = 1;
+static inline u32 netxen_get_interrupt_mode(struct netxen_adapter *adapter)
+{
+ return NXRD32(adapter, NETXEN_INTR_MODE_REG);
+}
- adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED);
+static void
+netxen_initialize_interrupt_registers(struct netxen_adapter *adapter)
+{
+ struct netxen_legacy_intr_set *legacy_intrp;
+ u32 tgt_status_reg, int_state_reg;
if (adapter->ahw.revision_id >= NX_P3_B0)
legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
else
legacy_intrp = &legacy_intr[0];
+ tgt_status_reg = legacy_intrp->tgt_status_reg;
+ int_state_reg = ISR_INT_STATE_REG;
+
adapter->int_vec_bit = legacy_intrp->int_vec_bit;
- adapter->tgt_status_reg = netxen_get_ioaddr(adapter,
- legacy_intrp->tgt_status_reg);
+ adapter->tgt_status_reg = netxen_get_ioaddr(adapter, tgt_status_reg);
adapter->tgt_mask_reg = netxen_get_ioaddr(adapter,
- legacy_intrp->tgt_mask_reg);
+ legacy_intrp->tgt_mask_reg);
adapter->pci_int_reg = netxen_get_ioaddr(adapter,
- legacy_intrp->pci_int_reg);
+ legacy_intrp->pci_int_reg);
adapter->isr_int_vec = netxen_get_ioaddr(adapter, ISR_INT_VECTOR);
if (adapter->ahw.revision_id >= NX_P3_B1)
adapter->crb_int_state_reg = netxen_get_ioaddr(adapter,
- ISR_INT_STATE_REG);
+ int_state_reg);
else
adapter->crb_int_state_reg = netxen_get_ioaddr(adapter,
- CRB_INT_VECTOR);
+ CRB_INT_VECTOR);
+}
- netxen_set_msix_bit(pdev, 0);
+static int netxen_setup_msi_interrupts(struct netxen_adapter *adapter,
+ int num_msix)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ u32 value;
+ int err;
if (adapter->msix_supported) {
-
netxen_init_msix_entries(adapter, num_msix);
err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
if (err == 0) {
@@ -644,26 +656,59 @@ netxen_setup_intr(struct netxen_adapter *adapter)
adapter->max_sds_rings = num_msix;
dev_info(&pdev->dev, "using msi-x interrupts\n");
- return;
+ return 0;
}
-
- if (err > 0)
- pci_disable_msix(pdev);
-
/* fall through for msi */
}
if (use_msi && !pci_enable_msi(pdev)) {
+ value = msi_tgt_status[adapter->ahw.pci_func];
adapter->flags |= NETXEN_NIC_MSI_ENABLED;
- adapter->tgt_status_reg = netxen_get_ioaddr(adapter,
- msi_tgt_status[adapter->ahw.pci_func]);
- dev_info(&pdev->dev, "using msi interrupts\n");
+ adapter->tgt_status_reg = netxen_get_ioaddr(adapter, value);
adapter->msix_entries[0].vector = pdev->irq;
- return;
+ dev_info(&pdev->dev, "using msi interrupts\n");
+ return 0;
}
- dev_info(&pdev->dev, "using legacy interrupts\n");
- adapter->msix_entries[0].vector = pdev->irq;
+ dev_err(&pdev->dev, "Failed to acquire MSI-X/MSI interrupt vector\n");
+ return -EIO;
+}
+
+static int netxen_setup_intr(struct netxen_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ int num_msix;
+
+ if (adapter->rss_supported)
+ num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
+ MSIX_ENTRIES_PER_ADAPTER : 2;
+ else
+ num_msix = 1;
+
+ adapter->max_sds_rings = 1;
+ adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED);
+
+ netxen_initialize_interrupt_registers(adapter);
+ netxen_set_msix_bit(pdev, 0);
+
+ if (netxen_function_zero(pdev)) {
+ if (!netxen_setup_msi_interrupts(adapter, num_msix))
+ netxen_set_interrupt_mode(adapter, NETXEN_MSI_MODE);
+ else
+ netxen_set_interrupt_mode(adapter, NETXEN_INTX_MODE);
+ } else {
+ if (netxen_get_interrupt_mode(adapter) == NETXEN_MSI_MODE &&
+ netxen_setup_msi_interrupts(adapter, num_msix)) {
+ dev_err(&pdev->dev, "Co-existence of MSI-X/MSI and INTx interrupts is not supported\n");
+ return -EIO;
+ }
+ }
+
+ if (!NETXEN_IS_MSI_FAMILY(adapter)) {
+ adapter->msix_entries[0].vector = pdev->irq;
+ dev_info(&pdev->dev, "using legacy interrupts\n");
+ }
+ return 0;
}
static void
@@ -841,7 +886,9 @@ netxen_check_options(struct netxen_adapter *adapter)
}
if (adapter->portnum == 0) {
- get_brd_name_by_type(adapter->ahw.board_type, brd_name);
+ if (netxen_nic_get_brd_name_by_type(adapter->ahw.board_type,
+ brd_name))
+ strcpy(serial_num, "Unknown");
pr_info("%s: %s Board S/N %s Chip rev 0x%x\n",
module_name(THIS_MODULE),
@@ -860,9 +907,9 @@ netxen_check_options(struct netxen_adapter *adapter)
adapter->ahw.cut_through = (i & 0x8000) ? 1 : 0;
}
- dev_info(&pdev->dev, "firmware v%d.%d.%d [%s]\n",
- fw_major, fw_minor, fw_build,
- adapter->ahw.cut_through ? "cut-through" : "legacy");
+ dev_info(&pdev->dev, "Driver v%s, firmware v%d.%d.%d [%s]\n",
+ NETXEN_NIC_LINUX_VERSIONID, fw_major, fw_minor, fw_build,
+ adapter->ahw.cut_through ? "cut-through" : "legacy");
if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222))
adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
@@ -1508,7 +1555,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netxen_nic_clear_stats(adapter);
- netxen_setup_intr(adapter);
+ err = netxen_setup_intr(adapter);
+
+ if (err) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to setup interrupts, error = %d\n", err);
+ goto err_out_disable_msi;
+ }
err = netxen_setup_netdev(adapter, netdev);
if (err)
@@ -1596,7 +1649,7 @@ static void netxen_nic_remove(struct pci_dev *pdev)
clear_bit(__NX_RESETTING, &adapter->state);
netxen_teardown_intr(adapter);
-
+ netxen_set_interrupt_mode(adapter, 0);
netxen_remove_diag_entries(adapter);
netxen_cleanup_pci_map(adapter);
@@ -2721,7 +2774,7 @@ netxen_store_bridged_mode(struct device *dev,
if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
goto err_out;
- if (strict_strtoul(buf, 2, &new))
+ if (kstrtoul(buf, 2, &new))
goto err_out;
if (!netxen_config_bridged_mode(adapter, !!new))
@@ -2760,7 +2813,7 @@ netxen_store_diag_mode(struct device *dev,
struct netxen_adapter *adapter = dev_get_drvdata(dev);
unsigned long new;
- if (strict_strtoul(buf, 2, &new))
+ if (kstrtoul(buf, 2, &new))
return -EINVAL;
if (!!new != !!(adapter->flags & NETXEN_NIC_DIAG_ENABLED))
@@ -3311,7 +3364,7 @@ static int netxen_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netxen_adapter *adapter;
- struct net_device *dev = (struct net_device *)ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct net_device *orig_dev = dev;
struct net_device *slave;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 90c253b..534e36e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -38,8 +38,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 2
-#define _QLCNIC_LINUX_SUBVERSION 42
-#define QLCNIC_LINUX_VERSIONID "5.2.42"
+#define _QLCNIC_LINUX_SUBVERSION 43
+#define QLCNIC_LINUX_VERSIONID "5.2.43"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -303,7 +303,6 @@ extern int qlcnic_use_msi;
extern int qlcnic_use_msi_x;
extern int qlcnic_auto_fw_reset;
extern int qlcnic_load_fw_file;
-extern int qlcnic_config_npars;
/* Number of status descriptors to handle per interrupt */
#define MAX_STATUS_HANDLE (64)
@@ -429,6 +428,7 @@ struct qlcnic_hardware_context {
u16 port_type;
u16 board_type;
+ u16 supported_type;
u16 link_speed;
u16 link_duplex;
@@ -442,6 +442,7 @@ struct qlcnic_hardware_context {
u16 max_mtu;
u32 msg_enable;
u16 act_pci_func;
+ u16 max_pci_func;
u32 capabilities;
u32 capabilities2;
@@ -815,6 +816,7 @@ struct qlcnic_mac_list_s {
#define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG BIT_2
#define QLCNIC_FW_CAP2_HW_LRO_IPV6 BIT_3
#define QLCNIC_FW_CAPABILITY_2_OCBB BIT_5
+#define QLCNIC_FW_CAPABILITY_2_BEACON BIT_7
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
@@ -906,8 +908,14 @@ struct qlcnic_ipaddr {
#define QLCNIC_FW_HANG 0x4000
#define QLCNIC_FW_LRO_MSS_CAP 0x8000
#define QLCNIC_TX_INTR_SHARED 0x10000
+#define QLCNIC_APP_CHANGED_FLAGS 0x20000
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
+#define QLCNIC_IS_TSO_CAPABLE(adapter) \
+ ((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+
+#define QLCNIC_BEACON_EANBLE 0xC
+#define QLCNIC_BEACON_DISABLE 0xD
#define QLCNIC_DEF_NUM_STS_DESC_RINGS 4
#define QLCNIC_MSIX_TBL_SPACE 8192
@@ -928,6 +936,7 @@ struct qlcnic_ipaddr {
#define __QLCNIC_SRIOV_ENABLE 10
#define __QLCNIC_SRIOV_CAPABLE 11
#define __QLCNIC_MBX_POLL_ENABLE 12
+#define __QLCNIC_DIAG_MODE 13
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
@@ -1033,6 +1042,7 @@ struct qlcnic_adapter {
spinlock_t rx_mac_learn_lock;
u32 file_prd_off; /*File fw product offset*/
u32 fw_version;
+ u32 offload_flags;
const struct firmware *fw;
};
@@ -1514,6 +1524,7 @@ void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
void qlcnic_82xx_add_sysfs(struct qlcnic_adapter *adapter);
void qlcnic_82xx_remove_sysfs(struct qlcnic_adapter *adapter);
+int qlcnic_82xx_get_settings(struct qlcnic_adapter *, struct ethtool_cmd *);
int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
@@ -1537,9 +1548,12 @@ int qlcnic_set_default_offload_settings(struct qlcnic_adapter *);
int qlcnic_reset_npar_config(struct qlcnic_adapter *);
int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *);
void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16);
+int qlcnic_get_beacon_state(struct qlcnic_adapter *, u8 *);
int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
int qlcnic_read_mac_addr(struct qlcnic_adapter *);
int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int);
+void qlcnic_set_netdev_features(struct qlcnic_adapter *,
+ struct qlcnic_esw_func_cfg *);
void qlcnic_sriov_vf_schedule_multi(struct net_device *);
void qlcnic_vf_add_mc_list(struct net_device *, u16);
@@ -1878,6 +1892,21 @@ static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
writel(0xfbff, adapter->tgt_mask_reg);
}
+static inline int qlcnic_get_diag_lock(struct qlcnic_adapter *adapter)
+{
+ return test_and_set_bit(__QLCNIC_DIAG_MODE, &adapter->state);
+}
+
+static inline void qlcnic_release_diag_lock(struct qlcnic_adapter *adapter)
+{
+ clear_bit(__QLCNIC_DIAG_MODE, &adapter->state);
+}
+
+static inline int qlcnic_check_diag_status(struct qlcnic_adapter *adapter)
+{
+ return test_bit(__QLCNIC_DIAG_MODE, &adapter->state);
+}
+
extern const struct ethtool_ops qlcnic_sriov_vf_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index ea790a9..f63a695 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -312,6 +312,11 @@ inline void qlcnic_83xx_clear_legacy_intr_mask(struct qlcnic_adapter *adapter)
writel(0, adapter->tgt_mask_reg);
}
+inline void qlcnic_83xx_set_legacy_intr_mask(struct qlcnic_adapter *adapter)
+{
+ writel(1, adapter->tgt_mask_reg);
+}
+
/* Enable MSI-x and INT-x interrupts */
void qlcnic_83xx_enable_intr(struct qlcnic_adapter *adapter,
struct qlcnic_host_sds_ring *sds_ring)
@@ -458,6 +463,9 @@ void qlcnic_83xx_free_mbx_intr(struct qlcnic_adapter *adapter)
{
u32 num_msix;
+ if (!(adapter->flags & QLCNIC_MSIX_ENABLED))
+ qlcnic_83xx_set_legacy_intr_mask(adapter);
+
qlcnic_83xx_disable_mbx_intr(adapter);
if (adapter->flags & QLCNIC_MSIX_ENABLED)
@@ -474,7 +482,6 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
{
irq_handler_t handler;
u32 val;
- char name[32];
int err = 0;
unsigned long flags = 0;
@@ -485,9 +492,7 @@ int qlcnic_83xx_setup_mbx_intr(struct qlcnic_adapter *adapter)
if (adapter->flags & QLCNIC_MSIX_ENABLED) {
handler = qlcnic_83xx_handle_aen;
val = adapter->msix_entries[adapter->ahw->num_msix - 1].vector;
- snprintf(name, (IFNAMSIZ + 4),
- "%s[%s]", "qlcnic", "aen");
- err = request_irq(val, handler, flags, name, adapter);
+ err = request_irq(val, handler, flags, "qlcnic-MB", adapter);
if (err) {
dev_err(&adapter->pdev->dev,
"failed to register MBX interrupt\n");
@@ -696,15 +701,14 @@ u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *adapter)
return 1;
}
-u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter)
+u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *adapter, u32 *wait_time)
{
u32 data;
- unsigned long wait_time = 0;
struct qlcnic_hardware_context *ahw = adapter->ahw;
/* wait for mailbox completion */
do {
data = QLCRDX(ahw, QLCNIC_FW_MBX_CTRL);
- if (++wait_time > QLCNIC_MBX_TIMEOUT) {
+ if (++(*wait_time) > QLCNIC_MBX_TIMEOUT) {
data = QLCNIC_RCODE_TIMEOUT;
break;
}
@@ -720,8 +724,8 @@ int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
u16 opcode;
u8 mbx_err_code;
unsigned long flags;
- u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd;
struct qlcnic_hardware_context *ahw = adapter->ahw;
+ u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, wait_time = 0;
opcode = LSW(cmd->req.arg[0]);
if (!test_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status)) {
@@ -754,15 +758,13 @@ int qlcnic_83xx_mbx_op(struct qlcnic_adapter *adapter,
/* Signal FW about the impending command */
QLCWRX(ahw, QLCNIC_HOST_MBX_CTRL, QLCNIC_SET_OWNER);
poll:
- rsp = qlcnic_83xx_mbx_poll(adapter);
+ rsp = qlcnic_83xx_mbx_poll(adapter, &wait_time);
if (rsp != QLCNIC_RCODE_TIMEOUT) {
/* Get the FW response data */
fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
if (fw_data & QLCNIC_MBX_ASYNC_EVENT) {
__qlcnic_83xx_process_aen(adapter);
- mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
- if (mbx_val)
- goto poll;
+ goto poll;
}
mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
@@ -1276,11 +1278,13 @@ out:
return err;
}
-static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test)
+static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test,
+ int num_sds_ring)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_host_rds_ring *rds_ring;
+ u16 adapter_state = adapter->is_up;
u8 ring;
int ret;
@@ -1304,6 +1308,10 @@ static int qlcnic_83xx_diag_alloc_res(struct net_device *netdev, int test)
ret = qlcnic_fw_create_ctx(adapter);
if (ret) {
qlcnic_detach(adapter);
+ if (adapter_state == QLCNIC_ADAPTER_UP_MAGIC) {
+ adapter->max_sds_rings = num_sds_ring;
+ qlcnic_attach(adapter);
+ }
netif_device_attach(netdev);
return ret;
}
@@ -1585,18 +1593,27 @@ int qlcnic_83xx_loopback_test(struct net_device *netdev, u8 mode)
struct qlcnic_hardware_context *ahw = adapter->ahw;
int ret = 0, loop = 0, max_sds_rings = adapter->max_sds_rings;
- QLCDB(adapter, DRV, "%s loopback test in progress\n",
- mode == QLCNIC_ILB_MODE ? "internal" : "external");
if (ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
- dev_warn(&adapter->pdev->dev,
- "Loopback test not supported for non privilege function\n");
+ netdev_warn(netdev,
+ "Loopback test not supported in non privileged mode\n");
return ret;
}
- if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+ netdev_info(netdev, "Device is resetting\n");
+ return -EBUSY;
+ }
+
+ if (qlcnic_get_diag_lock(adapter)) {
+ netdev_info(netdev, "Device is in diagnostics mode\n");
return -EBUSY;
+ }
+
+ netdev_info(netdev, "%s loopback test in progress\n",
+ mode == QLCNIC_ILB_MODE ? "internal" : "external");
- ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST);
+ ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_LOOPBACK_TEST,
+ max_sds_rings);
if (ret)
goto fail_diag_alloc;
@@ -1634,7 +1651,7 @@ free_diag_res:
fail_diag_alloc:
adapter->max_sds_rings = max_sds_rings;
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ qlcnic_release_diag_lock(adapter);
return ret;
}
@@ -2117,26 +2134,25 @@ out:
int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
struct qlcnic_pci_info *pci_info)
{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ struct device *dev = &adapter->pdev->dev;
+ struct qlcnic_cmd_args cmd;
int i, err = 0, j = 0;
u32 temp;
- struct qlcnic_cmd_args cmd;
qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_PCI_INFO);
err = qlcnic_issue_cmd(adapter, &cmd);
- adapter->ahw->act_pci_func = 0;
+ ahw->act_pci_func = 0;
if (err == QLCNIC_RCODE_SUCCESS) {
- pci_info->func_count = cmd.rsp.arg[1] & 0xFF;
- dev_info(&adapter->pdev->dev,
- "%s: total functions = %d\n",
- __func__, pci_info->func_count);
+ ahw->max_pci_func = cmd.rsp.arg[1] & 0xFF;
for (i = 2, j = 0; j < QLCNIC_MAX_PCI_FUNC; j++, pci_info++) {
pci_info->id = cmd.rsp.arg[i] & 0xFFFF;
pci_info->active = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
i++;
pci_info->type = cmd.rsp.arg[i] & 0xFFFF;
if (pci_info->type == QLCNIC_TYPE_NIC)
- adapter->ahw->act_pci_func++;
+ ahw->act_pci_func++;
temp = (cmd.rsp.arg[i] & 0xFFFF0000) >> 16;
pci_info->default_port = temp;
i++;
@@ -2148,18 +2164,21 @@ int qlcnic_83xx_get_pci_info(struct qlcnic_adapter *adapter,
i++;
memcpy(pci_info->mac + sizeof(u32), &cmd.rsp.arg[i], 2);
i = i + 3;
-
- dev_info(&adapter->pdev->dev, "%s:\n"
- "\tid = %d active = %d type = %d\n"
- "\tport = %d min bw = %d max bw = %d\n"
- "\tmac_addr = %pM\n", __func__,
- pci_info->id, pci_info->active, pci_info->type,
- pci_info->default_port, pci_info->tx_min_bw,
- pci_info->tx_max_bw, pci_info->mac);
+ if (ahw->op_mode == QLCNIC_MGMT_FUNC)
+ dev_info(dev, "id = %d active = %d type = %d\n"
+ "\tport = %d min bw = %d max bw = %d\n"
+ "\tmac_addr = %pM\n", pci_info->id,
+ pci_info->active, pci_info->type,
+ pci_info->default_port,
+ pci_info->tx_min_bw,
+ pci_info->tx_max_bw, pci_info->mac);
}
+ if (ahw->op_mode == QLCNIC_MGMT_FUNC)
+ dev_info(dev, "Max vNIC functions = %d, active vNIC functions = %d\n",
+ ahw->max_pci_func, ahw->act_pci_func);
+
} else {
- dev_err(&adapter->pdev->dev, "Failed to get PCI Info%d\n",
- err);
+ dev_err(dev, "Failed to get PCI Info, error = %d\n", err);
err = -EIO;
}
@@ -2830,6 +2849,23 @@ int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
break;
}
config = cmd.rsp.arg[3];
+ if (QLC_83XX_SFP_PRESENT(config)) {
+ switch (ahw->module_type) {
+ case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
+ case LINKEVENT_MODULE_OPTICAL_SRLR:
+ case LINKEVENT_MODULE_OPTICAL_LRM:
+ case LINKEVENT_MODULE_OPTICAL_SFP_1G:
+ ahw->supported_type = PORT_FIBRE;
+ break;
+ case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
+ case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
+ case LINKEVENT_MODULE_TWINAX:
+ ahw->supported_type = PORT_TP;
+ break;
+ default:
+ ahw->supported_type = PORT_OTHER;
+ }
+ }
if (config & 1)
err = 1;
}
@@ -2838,7 +2874,8 @@ out:
return config;
}
-int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter)
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
+ struct ethtool_cmd *ecmd)
{
u32 config = 0;
int status = 0;
@@ -2851,6 +2888,54 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter)
ahw->module_type = QLC_83XX_SFP_MODULE_TYPE(config);
/* hard code until there is a way to get it from flash */
ahw->board_type = QLCNIC_BRDTYPE_83XX_10G;
+
+ if (netif_running(adapter->netdev) && ahw->has_link_events) {
+ ethtool_cmd_speed_set(ecmd, ahw->link_speed);
+ ecmd->duplex = ahw->link_duplex;
+ ecmd->autoneg = ahw->link_autoneg;
+ } else {
+ ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
+ ecmd->duplex = DUPLEX_UNKNOWN;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ }
+
+ if (ahw->port_type == QLCNIC_XGBE) {
+ ecmd->supported = SUPPORTED_1000baseT_Full;
+ ecmd->advertising = ADVERTISED_1000baseT_Full;
+ } else {
+ ecmd->supported = (SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full);
+ ecmd->advertising = (ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full);
+ }
+
+ switch (ahw->supported_type) {
+ case PORT_FIBRE:
+ ecmd->supported |= SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_FIBRE;
+ ecmd->port = PORT_FIBRE;
+ ecmd->transceiver = XCVR_EXTERNAL;
+ break;
+ case PORT_TP:
+ ecmd->supported |= SUPPORTED_TP;
+ ecmd->advertising |= ADVERTISED_TP;
+ ecmd->port = PORT_TP;
+ ecmd->transceiver = XCVR_INTERNAL;
+ break;
+ default:
+ ecmd->supported |= SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_FIBRE;
+ ecmd->port = PORT_OTHER;
+ ecmd->transceiver = XCVR_EXTERNAL;
+ break;
+ }
+ ecmd->phy_address = ahw->physical_port;
return status;
}
@@ -3043,10 +3128,13 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev)
u8 val;
int ret, max_sds_rings = adapter->max_sds_rings;
- if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
- return -EIO;
+ if (qlcnic_get_diag_lock(adapter)) {
+ netdev_info(netdev, "Device in diagnostics mode\n");
+ return -EBUSY;
+ }
- ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST);
+ ret = qlcnic_83xx_diag_alloc_res(netdev, QLCNIC_INTERRUPT_TEST,
+ max_sds_rings);
if (ret)
goto fail_diag_irq;
@@ -3085,7 +3173,7 @@ done:
fail_diag_irq:
adapter->max_sds_rings = max_sds_rings;
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ qlcnic_release_diag_lock(adapter);
return ret;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 1f1d85e..1bfe283 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -314,6 +314,7 @@ struct qlc_83xx_idc {
u8 vnic_state;
u8 vnic_wait_limit;
u8 quiesce_req;
+ u8 delay_reset;
char **name;
};
@@ -603,7 +604,7 @@ int qlcnic_83xx_get_vnic_pf_info(struct qlcnic_adapter *, struct qlcnic_info *);
void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *);
void qlcnic_83xx_get_stats(struct qlcnic_adapter *adapter, u64 *data);
-int qlcnic_83xx_get_settings(struct qlcnic_adapter *);
+int qlcnic_83xx_get_settings(struct qlcnic_adapter *, struct ethtool_cmd *);
int qlcnic_83xx_set_settings(struct qlcnic_adapter *, struct ethtool_cmd *);
void qlcnic_83xx_get_pauseparam(struct qlcnic_adapter *,
struct ethtool_pauseparam *);
@@ -620,7 +621,7 @@ int qlcnic_83xx_flash_test(struct qlcnic_adapter *);
int qlcnic_83xx_enable_flash_write(struct qlcnic_adapter *);
int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *);
u32 qlcnic_83xx_mac_rcode(struct qlcnic_adapter *);
-u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *);
+u32 qlcnic_83xx_mbx_poll(struct qlcnic_adapter *, u32 *);
void qlcnic_83xx_enable_mbx_poll(struct qlcnic_adapter *);
void qlcnic_83xx_disable_mbx_poll(struct qlcnic_adapter *);
#endif
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index ab1d8d9..aa26250 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -382,8 +382,6 @@ static int qlcnic_83xx_idc_tx_soft_reset(struct qlcnic_adapter *adapter)
clear_bit(__QLCNIC_RESETTING, &adapter->state);
dev_err(&adapter->pdev->dev, "%s:\n", __func__);
- adapter->netdev->trans_start = jiffies;
-
return 0;
}
@@ -435,10 +433,6 @@ static void qlcnic_83xx_idc_attach_driver(struct qlcnic_adapter *adapter)
}
done:
netif_device_attach(netdev);
- if (netif_running(netdev)) {
- netif_carrier_on(netdev);
- netif_wake_queue(netdev);
- }
}
static int qlcnic_83xx_idc_enter_failed_state(struct qlcnic_adapter *adapter,
@@ -642,15 +636,22 @@ static int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
static void qlcnic_83xx_idc_update_idc_params(struct qlcnic_adapter *adapter)
{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+
qlcnic_83xx_idc_update_drv_presence_reg(adapter, 1, 1);
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
set_bit(QLC_83XX_MODULE_LOADED, &adapter->ahw->idc.status);
- adapter->ahw->idc.quiesce_req = 0;
- adapter->ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
- adapter->ahw->idc.err_code = 0;
- adapter->ahw->idc.collect_dump = 0;
+
+ ahw->idc.quiesce_req = 0;
+ ahw->idc.delay = QLC_83XX_IDC_FW_POLL_DELAY;
+ ahw->idc.err_code = 0;
+ ahw->idc.collect_dump = 0;
+ ahw->reset_context = 0;
+ adapter->tx_timeo_cnt = 0;
+ ahw->idc.delay_reset = 0;
+
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
}
/**
@@ -851,6 +852,7 @@ static int qlcnic_83xx_idc_ready_state(struct qlcnic_adapter *adapter)
/* Check for soft reset request */
if (ahw->reset_context &&
!(val & QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY)) {
+ adapter->ahw->reset_context = 0;
qlcnic_83xx_idc_tx_soft_reset(adapter);
return ret;
}
@@ -882,21 +884,41 @@ static int qlcnic_83xx_idc_need_reset_state(struct qlcnic_adapter *adapter)
int ret = 0;
if (adapter->ahw->idc.prev_state != QLC_83XX_IDC_DEV_NEED_RESET) {
- qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
qlcnic_83xx_idc_update_audit_reg(adapter, 0, 1);
set_bit(__QLCNIC_RESETTING, &adapter->state);
clear_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
if (adapter->ahw->nic_mode == QLC_83XX_VIRTUAL_NIC_MODE)
qlcnic_83xx_disable_vnic_mode(adapter, 1);
- qlcnic_83xx_idc_detach_driver(adapter);
+
+ if (qlcnic_check_diag_status(adapter)) {
+ dev_info(&adapter->pdev->dev,
+ "%s: Wait for diag completion\n", __func__);
+ adapter->ahw->idc.delay_reset = 1;
+ return 0;
+ } else {
+ qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+ qlcnic_83xx_idc_detach_driver(adapter);
+ }
}
- /* Check ACK from other functions */
- ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
- if (ret) {
+ if (qlcnic_check_diag_status(adapter)) {
dev_info(&adapter->pdev->dev,
- "%s: Waiting for reset ACK\n", __func__);
- return 0;
+ "%s: Wait for diag completion\n", __func__);
+ return -1;
+ } else {
+ if (adapter->ahw->idc.delay_reset) {
+ qlcnic_83xx_idc_update_drv_ack_reg(adapter, 1, 1);
+ qlcnic_83xx_idc_detach_driver(adapter);
+ adapter->ahw->idc.delay_reset = 0;
+ }
+
+ /* Check for ACK from other functions */
+ ret = qlcnic_83xx_idc_check_reset_ack_reg(adapter);
+ if (ret) {
+ dev_info(&adapter->pdev->dev,
+ "%s: Waiting for reset ACK\n", __func__);
+ return -1;
+ }
}
/* Transit to INIT state and restart the HW */
@@ -914,6 +936,7 @@ static int qlcnic_83xx_idc_need_quiesce_state(struct qlcnic_adapter *adapter)
static int qlcnic_83xx_idc_failed_state(struct qlcnic_adapter *adapter)
{
dev_err(&adapter->pdev->dev, "%s: please restart!!\n", __func__);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
adapter->ahw->idc.err_code = -EIO;
return 0;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
index b0c3de9..b5054e1 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
@@ -42,27 +42,18 @@ int qlcnic_83xx_disable_vnic_mode(struct qlcnic_adapter *adapter, int lock)
static int qlcnic_83xx_set_vnic_opmode(struct qlcnic_adapter *adapter)
{
u8 id;
- int i, ret = -EBUSY;
+ int ret = -EBUSY;
u32 data = QLCNIC_MGMT_FUNC;
struct qlcnic_hardware_context *ahw = adapter->ahw;
if (qlcnic_83xx_lock_driver(adapter))
return ret;
- if (qlcnic_config_npars) {
- for (i = 0; i < ahw->act_pci_func; i++) {
- id = adapter->npars[i].pci_func;
- if (id == ahw->pci_func)
- continue;
- data |= qlcnic_config_npars &
- QLC_83XX_SET_FUNC_OPMODE(0x3, id);
- }
- } else {
- data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
- data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, ahw->pci_func)) |
- QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC,
- ahw->pci_func);
- }
+ id = ahw->pci_func;
+ data = QLCRDX(adapter->ahw, QLC_83XX_DRV_OP_MODE);
+ data = (data & ~QLC_83XX_SET_FUNC_OPMODE(0x3, id)) |
+ QLC_83XX_SET_FUNC_OPMODE(QLCNIC_MGMT_FUNC, id);
+
QLCWRX(adapter->ahw, QLC_83XX_DRV_OP_MODE, data);
qlcnic_83xx_unlock_driver(adapter);
@@ -196,20 +187,24 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
else
priv_level = QLC_83XX_GET_FUNC_PRIVILEGE(op_mode,
ahw->pci_func);
-
- if (priv_level == QLCNIC_NON_PRIV_FUNC) {
+ switch (priv_level) {
+ case QLCNIC_NON_PRIV_FUNC:
ahw->op_mode = QLCNIC_NON_PRIV_FUNC;
ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
nic_ops->init_driver = qlcnic_83xx_init_non_privileged_vnic;
- } else if (priv_level == QLCNIC_PRIV_FUNC) {
+ break;
+ case QLCNIC_PRIV_FUNC:
ahw->op_mode = QLCNIC_PRIV_FUNC;
ahw->idc.state_entry = qlcnic_83xx_idc_vnic_pf_entry;
nic_ops->init_driver = qlcnic_83xx_init_privileged_vnic;
- } else if (priv_level == QLCNIC_MGMT_FUNC) {
+ break;
+ case QLCNIC_MGMT_FUNC:
ahw->op_mode = QLCNIC_MGMT_FUNC;
ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry;
nic_ops->init_driver = qlcnic_83xx_init_mgmt_vnic;
- } else {
+ break;
+ default:
+ dev_err(&adapter->pdev->dev, "Invalid Virtual NIC opmode\n");
return -EIO;
}
@@ -218,8 +213,8 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter)
else
adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
- adapter->ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
- adapter->ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
+ ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER;
+ ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO;
return 0;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index 43562c2..9d0ae11 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -37,6 +37,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_mbx_tbl[] = {
{QLCNIC_CMD_TEMP_SIZE, 4, 4},
{QLCNIC_CMD_GET_TEMP_HDR, 4, 1},
{QLCNIC_CMD_SET_DRV_VER, 4, 1},
+ {QLCNIC_CMD_GET_LED_STATUS, 4, 2},
};
static inline u32 qlcnic_get_cmd_signature(struct qlcnic_hardware_context *ahw)
@@ -882,11 +883,12 @@ int qlcnic_82xx_get_pci_info(struct qlcnic_adapter *adapter,
/* Configure eSwitch for port mirroring */
int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
- u8 enable_mirroring, u8 pci_func)
+ u8 enable_mirroring, u8 pci_func)
{
+ struct device *dev = &adapter->pdev->dev;
+ struct qlcnic_cmd_args cmd;
int err = -EIO;
u32 arg1;
- struct qlcnic_cmd_args cmd;
if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC ||
!(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
@@ -900,13 +902,11 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
err = qlcnic_issue_cmd(adapter, &cmd);
if (err != QLCNIC_RCODE_SUCCESS)
- dev_err(&adapter->pdev->dev,
- "Failed to configure port mirroring%d on eswitch:%d\n",
+ dev_err(dev, "Failed to configure port mirroring for vNIC function %d on eSwitch %d\n",
pci_func, id);
else
- dev_info(&adapter->pdev->dev,
- "Configured eSwitch %d for port mirroring:%d\n",
- id, pci_func);
+ dev_info(dev, "Configured port mirroring for vNIC function %d on eSwitch %d\n",
+ pci_func, id);
qlcnic_free_mbx_args(&cmd);
return err;
@@ -1121,14 +1121,13 @@ err_ret:
return -EIO;
}
-static int
-__qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
- u32 *arg1, u32 *arg2)
+static int __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
+ u32 *arg1, u32 *arg2)
{
- int err = -EIO;
+ struct device *dev = &adapter->pdev->dev;
struct qlcnic_cmd_args cmd;
- u8 pci_func;
- pci_func = (*arg1 >> 8);
+ u8 pci_func = *arg1 >> 8;
+ int err = -EIO;
qlcnic_alloc_mbx_args(&cmd, adapter,
QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG);
@@ -1139,12 +1138,11 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
qlcnic_free_mbx_args(&cmd);
if (err == QLCNIC_RCODE_SUCCESS)
- dev_info(&adapter->pdev->dev,
- "eSwitch port config for pci func %d\n", pci_func);
+ dev_info(dev, "Get eSwitch port config for vNIC function %d\n",
+ pci_func);
else
- dev_err(&adapter->pdev->dev,
- "Failed to get eswitch port config for pci func %d\n",
- pci_func);
+ dev_err(dev, "Failed to get eswitch port config for vNIC function %d\n",
+ pci_func);
return err;
}
/* Configure eSwitch port
@@ -1157,9 +1155,10 @@ op_type = 1 for port vlan_id
int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
struct qlcnic_esw_func_cfg *esw_cfg)
{
+ struct device *dev = &adapter->pdev->dev;
+ struct qlcnic_cmd_args cmd;
int err = -EIO, index;
u32 arg1, arg2 = 0;
- struct qlcnic_cmd_args cmd;
u8 pci_func;
if (adapter->ahw->op_mode != QLCNIC_MGMT_FUNC)
@@ -1216,11 +1215,11 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
qlcnic_free_mbx_args(&cmd);
if (err != QLCNIC_RCODE_SUCCESS)
- dev_err(&adapter->pdev->dev,
- "Failed to configure eswitch pci func %d\n", pci_func);
+ dev_err(dev, "Failed to configure eswitch for vNIC function %d\n",
+ pci_func);
else
- dev_info(&adapter->pdev->dev,
- "Configured eSwitch for pci func %d\n", pci_func);
+ dev_info(dev, "Configured eSwitch for vNIC function %d\n",
+ pci_func);
return err;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
index 08efb46..f67652d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
@@ -131,12 +131,13 @@ static const char qlcnic_83xx_rx_stats_strings[][ETH_GSTRING_LEN] = {
"ctx_lro_pkt_cnt",
"ctx_ip_csum_error",
"ctx_rx_pkts_wo_ctx",
- "ctx_rx_pkts_dropped_wo_sts",
+ "ctx_rx_pkts_drop_wo_sds_on_card",
+ "ctx_rx_pkts_drop_wo_sds_on_host",
"ctx_rx_osized_pkts",
"ctx_rx_pkts_dropped_wo_rds",
"ctx_rx_unexpected_mcast_pkts",
"ctx_invalid_mac_address",
- "ctx_rx_rds_ring_prim_attemoted",
+ "ctx_rx_rds_ring_prim_attempted",
"ctx_rx_rds_ring_prim_success",
"ctx_num_lro_flows_added",
"ctx_num_lro_flows_removed",
@@ -251,6 +252,18 @@ static int
qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+ if (qlcnic_82xx_check(adapter))
+ return qlcnic_82xx_get_settings(adapter, ecmd);
+ else if (qlcnic_83xx_check(adapter))
+ return qlcnic_83xx_get_settings(adapter, ecmd);
+
+ return -EIO;
+}
+
+int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
+ struct ethtool_cmd *ecmd)
+{
struct qlcnic_hardware_context *ahw = adapter->ahw;
u32 speed, reg;
int check_sfp_module = 0;
@@ -276,10 +289,7 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
} else if (adapter->ahw->port_type == QLCNIC_XGBE) {
u32 val = 0;
- if (qlcnic_83xx_check(adapter))
- qlcnic_83xx_get_settings(adapter);
- else
- val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
+ val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
if (val == QLCNIC_PORT_MODE_802_3_AP) {
ecmd->supported = SUPPORTED_1000baseT_Full;
@@ -289,16 +299,13 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->advertising = ADVERTISED_10000baseT_Full;
}
- if (netif_running(dev) && adapter->ahw->has_link_events) {
- if (qlcnic_82xx_check(adapter)) {
- reg = QLCRD32(adapter,
- P3P_LINK_SPEED_REG(pcifn));
- speed = P3P_LINK_SPEED_VAL(pcifn, reg);
- ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
- }
- ethtool_cmd_speed_set(ecmd, adapter->ahw->link_speed);
- ecmd->autoneg = adapter->ahw->link_autoneg;
- ecmd->duplex = adapter->ahw->link_duplex;
+ if (netif_running(adapter->netdev) && ahw->has_link_events) {
+ reg = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
+ speed = P3P_LINK_SPEED_VAL(pcifn, reg);
+ ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+ ethtool_cmd_speed_set(ecmd, ahw->link_speed);
+ ecmd->autoneg = ahw->link_autoneg;
+ ecmd->duplex = ahw->link_duplex;
goto skip;
}
@@ -340,8 +347,8 @@ skip:
case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
ecmd->advertising |= ADVERTISED_TP;
ecmd->supported |= SUPPORTED_TP;
- check_sfp_module = netif_running(dev) &&
- adapter->ahw->has_link_events;
+ check_sfp_module = netif_running(adapter->netdev) &&
+ ahw->has_link_events;
case QLCNIC_BRDTYPE_P3P_10G_XFP:
ecmd->supported |= SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_FIBRE;
@@ -355,8 +362,8 @@ skip:
ecmd->advertising |=
(ADVERTISED_FIBRE | ADVERTISED_TP);
ecmd->port = PORT_FIBRE;
- check_sfp_module = netif_running(dev) &&
- adapter->ahw->has_link_events;
+ check_sfp_module = netif_running(adapter->netdev) &&
+ ahw->has_link_events;
} else {
ecmd->autoneg = AUTONEG_ENABLE;
ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
@@ -365,13 +372,6 @@ skip:
ecmd->port = PORT_TP;
}
break;
- case QLCNIC_BRDTYPE_83XX_10G:
- ecmd->autoneg = AUTONEG_DISABLE;
- ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
- ecmd->advertising |= (ADVERTISED_FIBRE | ADVERTISED_TP);
- ecmd->port = PORT_FIBRE;
- check_sfp_module = netif_running(dev) && ahw->has_link_events;
- break;
default:
dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
adapter->ahw->board_type);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 6a6512b..218978d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -973,16 +973,57 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
return rc;
}
+static netdev_features_t qlcnic_process_flags(struct qlcnic_adapter *adapter,
+ netdev_features_t features)
+{
+ u32 offload_flags = adapter->offload_flags;
+
+ if (offload_flags & BIT_0) {
+ features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM;
+ adapter->rx_csum = 1;
+ if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
+ if (!(offload_flags & BIT_1))
+ features &= ~NETIF_F_TSO;
+ else
+ features |= NETIF_F_TSO;
+
+ if (!(offload_flags & BIT_2))
+ features &= ~NETIF_F_TSO6;
+ else
+ features |= NETIF_F_TSO6;
+ }
+ } else {
+ features &= ~(NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM);
+
+ if (QLCNIC_IS_TSO_CAPABLE(adapter))
+ features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ adapter->rx_csum = 0;
+ }
+
+ return features;
+}
netdev_features_t qlcnic_fix_features(struct net_device *netdev,
netdev_features_t features)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ netdev_features_t changed;
- if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) &&
- qlcnic_82xx_check(adapter)) {
- netdev_features_t changed = features ^ netdev->features;
- features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM);
+ if (qlcnic_82xx_check(adapter) &&
+ (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ if (adapter->flags & QLCNIC_APP_CHANGED_FLAGS) {
+ features = qlcnic_process_flags(adapter, features);
+ } else {
+ changed = features ^ netdev->features;
+ features ^= changed & (NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO |
+ NETIF_F_TSO6);
+ }
}
if (!(features & NETIF_F_RXCSUM))
@@ -1462,6 +1503,21 @@ int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
return rv;
}
+int qlcnic_get_beacon_state(struct qlcnic_adapter *adapter, u8 *h_state)
+{
+ struct qlcnic_cmd_args cmd;
+ int err;
+
+ err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_STATUS);
+ if (!err) {
+ err = qlcnic_issue_cmd(adapter, &cmd);
+ if (!err)
+ *h_state = cmd.rsp.arg[1];
+ }
+ qlcnic_free_mbx_args(&cmd);
+ return err;
+}
+
void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
{
void __iomem *msix_base_addr;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
index 95b1b57..812fd07 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
@@ -87,6 +87,7 @@ enum qlcnic_regs {
#define QLCNIC_CMD_CONFIG_VPORT 0x32
#define QLCNIC_CMD_GET_MAC_STATS 0x37
#define QLCNIC_CMD_SET_DRV_VER 0x38
+#define QLCNIC_CMD_GET_LED_STATUS 0x3C
#define QLCNIC_CMD_CONFIGURE_RSS 0x41
#define QLCNIC_CMD_CONFIG_INTR_COAL 0x43
#define QLCNIC_CMD_CONFIGURE_LED 0x44
@@ -134,7 +135,7 @@ struct qlcnic_mailbox_metadata {
#define QLCNIC_SET_OWNER 1
#define QLCNIC_CLR_OWNER 0
-#define QLCNIC_MBX_TIMEOUT 10000
+#define QLCNIC_MBX_TIMEOUT 5000
#define QLCNIC_MBX_RSP_OK 1
#define QLCNIC_MBX_PORT_RSP_OK 0x1a
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 264d5a4..0ae8835 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -37,25 +37,21 @@ MODULE_PARM_DESC(qlcnic_mac_learn,
"Mac Filter (0=learning is disabled, 1=Driver learning is enabled, 2=FDB learning is enabled)");
int qlcnic_use_msi = 1;
-MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
+MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled)");
module_param_named(use_msi, qlcnic_use_msi, int, 0444);
int qlcnic_use_msi_x = 1;
-MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled");
+MODULE_PARM_DESC(use_msi_x, "MSI-X interrupt (0=disabled, 1=enabled)");
module_param_named(use_msi_x, qlcnic_use_msi_x, int, 0444);
int qlcnic_auto_fw_reset = 1;
-MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled");
+MODULE_PARM_DESC(auto_fw_reset, "Auto firmware reset (0=disabled, 1=enabled)");
module_param_named(auto_fw_reset, qlcnic_auto_fw_reset, int, 0644);
int qlcnic_load_fw_file;
-MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
+MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file)");
module_param_named(load_fw_file, qlcnic_load_fw_file, int, 0444);
-int qlcnic_config_npars;
-module_param(qlcnic_config_npars, int, 0444);
-MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
-
static int qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static void qlcnic_remove(struct pci_dev *pdev);
static int qlcnic_open(struct net_device *netdev);
@@ -84,14 +80,9 @@ static int qlcnic_start_firmware(struct qlcnic_adapter *);
static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
-static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
- struct qlcnic_esw_func_cfg *);
static int qlcnic_vlan_rx_add(struct net_device *, __be16, u16);
static int qlcnic_vlan_rx_del(struct net_device *, __be16, u16);
-#define QLCNIC_IS_TSO_CAPABLE(adapter) \
- ((adapter)->ahw->capabilities & QLCNIC_FW_CAPABILITY_TSO)
-
static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
{
struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -308,6 +299,23 @@ int qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
return 0;
}
+static void qlcnic_delete_adapter_mac(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_mac_list_s *cur;
+ struct list_head *head;
+
+ list_for_each(head, &adapter->mac_list) {
+ cur = list_entry(head, struct qlcnic_mac_list_s, list);
+ if (!memcmp(adapter->mac_addr, cur->mac_addr, ETH_ALEN)) {
+ qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
+ 0, QLCNIC_MAC_DEL);
+ list_del(&cur->list);
+ kfree(cur);
+ return;
+ }
+ }
+}
+
static int qlcnic_set_mac(struct net_device *netdev, void *p)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -322,11 +330,15 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
+ if (!memcmp(adapter->mac_addr, addr->sa_data, ETH_ALEN))
+ return 0;
+
if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
netif_device_detach(netdev);
qlcnic_napi_disable(adapter);
}
+ qlcnic_delete_adapter_mac(adapter);
memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len);
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
qlcnic_set_multi(adapter->netdev);
@@ -433,6 +445,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_set_vf_tx_rate = qlcnic_sriov_set_vf_tx_rate,
.ndo_get_vf_config = qlcnic_sriov_get_vf_config,
.ndo_set_vf_vlan = qlcnic_sriov_set_vf_vlan,
+ .ndo_set_vf_spoofchk = qlcnic_sriov_set_vf_spoofchk,
#endif
};
@@ -752,7 +765,7 @@ static int
qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
{
u8 id;
- int i, ret = 1;
+ int ret;
u32 data = QLCNIC_MGMT_FUNC;
struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -760,20 +773,10 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
if (ret)
goto err_lock;
- if (qlcnic_config_npars) {
- for (i = 0; i < ahw->act_pci_func; i++) {
- id = adapter->npars[i].pci_func;
- if (id == ahw->pci_func)
- continue;
- data |= (qlcnic_config_npars &
- QLC_DEV_SET_DRV(0xf, id));
- }
- } else {
- data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
- data = (data & ~QLC_DEV_SET_DRV(0xf, ahw->pci_func)) |
- (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
- ahw->pci_func));
- }
+ id = ahw->pci_func;
+ data = QLC_SHARED_REG_RD32(adapter, QLCNIC_DRV_OP_MODE);
+ data = (data & ~QLC_DEV_SET_DRV(0xf, id)) |
+ QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, id);
QLC_SHARED_REG_WR32(adapter, QLCNIC_DRV_OP_MODE, data);
qlcnic_api_unlock(adapter);
err_lock:
@@ -859,6 +862,27 @@ static int qlcnic_setup_pci_map(struct pci_dev *pdev,
return 0;
}
+static inline bool qlcnic_validate_subsystem_id(struct qlcnic_adapter *adapter,
+ int index)
+{
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned short subsystem_vendor;
+ bool ret = true;
+
+ subsystem_vendor = pdev->subsystem_vendor;
+
+ if (pdev->device == PCI_DEVICE_ID_QLOGIC_QLE824X ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_QLE834X) {
+ if (qlcnic_boards[index].sub_vendor == subsystem_vendor &&
+ qlcnic_boards[index].sub_device == pdev->subsystem_device)
+ ret = true;
+ else
+ ret = false;
+ }
+
+ return ret;
+}
+
static void qlcnic_get_board_name(struct qlcnic_adapter *adapter, char *name)
{
struct pci_dev *pdev = adapter->pdev;
@@ -866,20 +890,18 @@ static void qlcnic_get_board_name(struct qlcnic_adapter *adapter, char *name)
for (i = 0; i < NUM_SUPPORTED_BOARDS; ++i) {
if (qlcnic_boards[i].vendor == pdev->vendor &&
- qlcnic_boards[i].device == pdev->device &&
- qlcnic_boards[i].sub_vendor == pdev->subsystem_vendor &&
- qlcnic_boards[i].sub_device == pdev->subsystem_device) {
- sprintf(name, "%pM: %s" ,
- adapter->mac_addr,
- qlcnic_boards[i].short_name);
- found = 1;
- break;
+ qlcnic_boards[i].device == pdev->device &&
+ qlcnic_validate_subsystem_id(adapter, i)) {
+ found = 1;
+ break;
}
-
}
if (!found)
sprintf(name, "%pM Gigabit Ethernet", adapter->mac_addr);
+ else
+ sprintf(name, "%pM: %s" , adapter->mac_addr,
+ qlcnic_boards[i].short_name);
}
static void
@@ -1053,8 +1075,6 @@ void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
if (!esw_cfg->promisc_mode)
adapter->flags |= QLCNIC_PROMISC_DISABLED;
-
- qlcnic_set_netdev_features(adapter, esw_cfg);
}
int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
@@ -1069,51 +1089,23 @@ int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
return -EIO;
qlcnic_set_vlan_config(adapter, &esw_cfg);
qlcnic_set_eswitch_port_features(adapter, &esw_cfg);
+ qlcnic_set_netdev_features(adapter, &esw_cfg);
return 0;
}
-static void
-qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
- struct qlcnic_esw_func_cfg *esw_cfg)
+void qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg)
{
struct net_device *netdev = adapter->netdev;
- unsigned long features, vlan_features;
if (qlcnic_83xx_check(adapter))
return;
- features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
- NETIF_F_IPV6_CSUM | NETIF_F_GRO);
- vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM);
-
- if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
- features |= (NETIF_F_TSO | NETIF_F_TSO6);
- vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
- }
-
- if (netdev->features & NETIF_F_LRO)
- features |= NETIF_F_LRO;
-
- if (esw_cfg->offload_flags & BIT_0) {
- netdev->features |= features;
- adapter->rx_csum = 1;
- if (!(esw_cfg->offload_flags & BIT_1)) {
- netdev->features &= ~NETIF_F_TSO;
- features &= ~NETIF_F_TSO;
- }
- if (!(esw_cfg->offload_flags & BIT_2)) {
- netdev->features &= ~NETIF_F_TSO6;
- features &= ~NETIF_F_TSO6;
- }
- } else {
- netdev->features &= ~features;
- features &= ~features;
- adapter->rx_csum = 0;
- }
-
- netdev->vlan_features = (features & vlan_features);
+ adapter->offload_flags = esw_cfg->offload_flags;
+ adapter->flags |= QLCNIC_APP_CHANGED_FLAGS;
+ netdev_update_features(netdev);
+ adapter->flags &= ~QLCNIC_APP_CHANGED_FLAGS;
}
static int
@@ -1409,16 +1401,23 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
for (ring = 0; ring < num_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
if (qlcnic_82xx_check(adapter) &&
- (ring == (num_sds_rings - 1)))
+ (ring == (num_sds_rings - 1))) {
+ if (!(adapter->flags &
+ QLCNIC_MSIX_ENABLED))
+ snprintf(sds_ring->name,
+ sizeof(sds_ring->name),
+ "qlcnic");
+ else
+ snprintf(sds_ring->name,
+ sizeof(sds_ring->name),
+ "%s-tx-0-rx-%d",
+ netdev->name, ring);
+ } else {
snprintf(sds_ring->name,
sizeof(sds_ring->name),
- "qlcnic-%s[Tx0+Rx%d]",
- netdev->name, ring);
- else
- snprintf(sds_ring->name,
- sizeof(sds_ring->name),
- "qlcnic-%s[Rx%d]",
+ "%s-rx-%d",
netdev->name, ring);
+ }
err = request_irq(sds_ring->irq, handler, flags,
sds_ring->name, sds_ring);
if (err)
@@ -1433,7 +1432,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
ring++) {
tx_ring = &adapter->tx_ring[ring];
snprintf(tx_ring->name, sizeof(tx_ring->name),
- "qlcnic-%s[Tx%d]", netdev->name, ring);
+ "%s-tx-%d", netdev->name, ring);
err = request_irq(tx_ring->irq, handler, flags,
tx_ring->name, tx_ring);
if (err)
@@ -1995,8 +1994,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_enable_pcie_error_reporting(pdev);
ahw = kzalloc(sizeof(struct qlcnic_hardware_context), GFP_KERNEL);
- if (!ahw)
+ if (!ahw) {
+ err = -ENOMEM;
goto err_out_free_res;
+ }
switch (ent->device) {
case PCI_DEVICE_ID_QLOGIC_QLE824X:
@@ -2032,6 +2033,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->qlcnic_wq = create_singlethread_workqueue("qlcnic");
if (adapter->qlcnic_wq == NULL) {
+ err = -ENOMEM;
dev_err(&pdev->dev, "Failed to create workqueue\n");
goto err_out_free_netdev;
}
@@ -2112,6 +2114,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_disable_msi;
}
+ err = qlcnic_get_act_pci_func(adapter);
+ if (err)
+ goto err_out_disable_mbx_intr;
+
err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
if (err)
goto err_out_disable_mbx_intr;
@@ -2141,9 +2147,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
- if (qlcnic_get_act_pci_func(adapter))
- goto err_out_disable_mbx_intr;
-
if (adapter->drv_mac_learn)
qlcnic_alloc_lb_filters_mem(adapter);
@@ -2481,12 +2484,17 @@ static void qlcnic_tx_timeout(struct net_device *netdev)
if (test_bit(__QLCNIC_RESETTING, &adapter->state))
return;
- dev_err(&netdev->dev, "transmit timeout, resetting.\n");
-
- if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS)
- adapter->need_fw_reset = 1;
- else
+ if (++adapter->tx_timeo_cnt >= QLCNIC_MAX_TX_TIMEOUTS) {
+ netdev_info(netdev, "Tx timeout, reset the adapter.\n");
+ if (qlcnic_82xx_check(adapter))
+ adapter->need_fw_reset = 1;
+ else if (qlcnic_83xx_check(adapter))
+ qlcnic_83xx_idc_request_reset(adapter,
+ QLCNIC_FORCE_FW_DUMP_KEY);
+ } else {
+ netdev_info(netdev, "Tx timeout, reset adapter context.\n");
adapter->ahw->reset_context = 1;
+ }
}
static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev)
@@ -3123,10 +3131,8 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
if (adapter->need_fw_reset)
goto detach;
- if (adapter->ahw->reset_context && qlcnic_auto_fw_reset) {
+ if (adapter->ahw->reset_context && qlcnic_auto_fw_reset)
qlcnic_reset_hw_context(adapter);
- adapter->netdev->trans_start = jiffies;
- }
return 0;
}
@@ -3226,7 +3232,6 @@ static int qlcnic_attach_func(struct pci_dev *pdev)
if (err)
return err;
- pci_set_power_state(pdev, PCI_D0);
pci_set_master(pdev);
pci_restore_state(pdev);
@@ -3524,7 +3529,7 @@ static int qlcnic_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct qlcnic_adapter *adapter;
- struct net_device *dev = (struct net_device *)ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
recheck:
if (dev == NULL)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
index d85fbb5..9176cb0 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h
@@ -129,6 +129,7 @@ struct qlcnic_vport {
u8 vlan_mode;
u16 vlan;
u8 qos;
+ bool spoofchk;
u8 mac[6];
};
@@ -225,6 +226,7 @@ int qlcnic_sriov_set_vf_tx_rate(struct net_device *, int, int);
int qlcnic_sriov_get_vf_config(struct net_device *, int ,
struct ifla_vf_info *);
int qlcnic_sriov_set_vf_vlan(struct net_device *, int, u16, u8);
+int qlcnic_sriov_set_vf_spoofchk(struct net_device *, int, bool);
#else
static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {}
static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 44d547d..bcd200e 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -35,6 +35,7 @@ static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *);
static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *);
static int qlcnic_sriov_vf_mbx_op(struct qlcnic_adapter *,
struct qlcnic_cmd_args *);
+static void qlcnic_sriov_process_bc_cmd(struct work_struct *);
static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = {
.read_crb = qlcnic_83xx_read_crb,
@@ -179,6 +180,8 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
spin_lock_init(&vf->rcv_pend.lock);
init_completion(&vf->ch_free_cmpl);
+ INIT_WORK(&vf->trans_work, qlcnic_sriov_process_bc_cmd);
+
if (qlcnic_sriov_pf_check(adapter)) {
vp = kzalloc(sizeof(struct qlcnic_vport), GFP_KERNEL);
if (!vp) {
@@ -187,6 +190,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs)
}
sriov->vf_info[i].vp = vp;
vp->max_tx_bw = MAX_BW;
+ vp->spoofchk = true;
random_ether_addr(vp->mac);
dev_info(&adapter->pdev->dev,
"MAC Address %pM is configured for VF %d\n",
@@ -280,9 +284,9 @@ void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter)
static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
u32 *pay, u8 pci_func, u8 size)
{
+ u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val, wait_time = 0;
struct qlcnic_hardware_context *ahw = adapter->ahw;
unsigned long flags;
- u32 rsp, mbx_val, fw_data, rsp_num, mbx_cmd, val;
u16 opcode;
u8 mbx_err_code;
int i, j;
@@ -330,15 +334,13 @@ static int qlcnic_sriov_post_bc_msg(struct qlcnic_adapter *adapter, u32 *hdr,
* assume something is wrong.
*/
poll:
- rsp = qlcnic_83xx_mbx_poll(adapter);
+ rsp = qlcnic_83xx_mbx_poll(adapter, &wait_time);
if (rsp != QLCNIC_RCODE_TIMEOUT) {
/* Get the FW response data */
fw_data = readl(QLCNIC_MBX_FW(ahw, 0));
if (fw_data & QLCNIC_MBX_ASYNC_EVENT) {
__qlcnic_83xx_process_aen(adapter);
- mbx_val = QLCRDX(ahw, QLCNIC_HOST_MBX_CTRL);
- if (mbx_val)
- goto poll;
+ goto poll;
}
mbx_err_code = QLCNIC_MBX_STATUS(fw_data);
rsp_num = QLCNIC_MBX_NUM_REGS(fw_data);
@@ -654,6 +656,8 @@ int qlcnic_sriov_vf_init(struct qlcnic_adapter *adapter, int pci_using_dac)
if (qlcnic_read_mac_addr(adapter))
dev_warn(&adapter->pdev->dev, "failed to read mac addr\n");
+ INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
clear_bit(__QLCNIC_RESETTING, &adapter->state);
return 0;
}
@@ -866,7 +870,6 @@ static void qlcnic_sriov_schedule_bc_cmd(struct qlcnic_sriov *sriov,
vf->adapter->need_fw_reset)
return;
- INIT_WORK(&vf->trans_work, func);
queue_work(sriov->bc.bc_trans_wq, &vf->trans_work);
}
@@ -1736,7 +1739,6 @@ static int qlcnic_sriov_vf_handle_context_reset(struct qlcnic_adapter *adapter)
if (!qlcnic_sriov_vf_reinit_driver(adapter)) {
qlcnic_sriov_vf_attach(adapter);
- adapter->netdev->trans_start = jiffies;
adapter->tx_timeo_cnt = 0;
adapter->reset_ctx_cnt = 0;
adapter->fw_fail_cnt = 0;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index c81be2d..ee0c1d3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -580,6 +580,7 @@ static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func)
struct qlcnic_cmd_args cmd;
struct qlcnic_vport *vp;
int err, id;
+ u8 *mac;
id = qlcnic_sriov_func_to_index(adapter, func);
if (id < 0)
@@ -591,6 +592,14 @@ static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func)
return err;
cmd.req.arg[1] = 0x3 | func << 16;
+ if (vp->spoofchk == true) {
+ mac = vp->mac;
+ cmd.req.arg[2] |= BIT_1 | BIT_3 | BIT_8;
+ cmd.req.arg[4] = mac[5] | mac[4] << 8 | mac[3] << 16 |
+ mac[2] << 24;
+ cmd.req.arg[5] = mac[1] | mac[0] << 8;
+ }
+
if (vp->vlan_mode == QLC_PVID_MODE) {
cmd.req.arg[2] |= BIT_6;
cmd.req.arg[3] |= vp->vlan << 8;
@@ -1133,9 +1142,6 @@ static int qlcnic_sriov_validate_linkevent(struct qlcnic_vf_info *vf,
if ((cmd->req.arg[1] >> 16) != vf->rx_ctx_id)
return -EINVAL;
- if (!(cmd->req.arg[1] & BIT_8))
- return -EINVAL;
-
return 0;
}
@@ -1770,6 +1776,7 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,
memcpy(&ivi->mac, vp->mac, ETH_ALEN);
ivi->vlan = vp->vlan;
ivi->qos = vp->qos;
+ ivi->spoofchk = vp->spoofchk;
if (vp->max_tx_bw == MAX_BW)
ivi->tx_rate = 0;
else
@@ -1778,3 +1785,29 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,
ivi->vf = vf;
return 0;
}
+
+int qlcnic_sriov_set_vf_spoofchk(struct net_device *netdev, int vf, bool chk)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_sriov *sriov = adapter->ahw->sriov;
+ struct qlcnic_vf_info *vf_info;
+ struct qlcnic_vport *vp;
+
+ if (!qlcnic_sriov_pf_check(adapter))
+ return -EOPNOTSUPP;
+
+ if (vf >= sriov->num_vfs)
+ return -EINVAL;
+
+ vf_info = &sriov->vf_info[vf];
+ vp = vf_info->vp;
+ if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) {
+ netdev_err(netdev,
+ "Spoof check change failed for VF %d, as VF driver is loaded. Please unload VF driver and retry the operation\n",
+ vf);
+ return -EOPNOTSUPP;
+ }
+
+ vp->spoofchk = chk;
+ return 0;
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index 4e22e79..7ec030a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -47,7 +47,7 @@ static ssize_t qlcnic_store_bridged_mode(struct device *dev,
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
goto err_out;
- if (strict_strtoul(buf, 2, &new))
+ if (kstrtoul(buf, 2, &new))
goto err_out;
if (!qlcnic_config_bridged_mode(adapter, !!new))
@@ -77,7 +77,7 @@ static ssize_t qlcnic_store_diag_mode(struct device *dev,
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
unsigned long new;
- if (strict_strtoul(buf, 2, &new))
+ if (kstrtoul(buf, 2, &new))
return -EINVAL;
if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
@@ -114,57 +114,51 @@ static int qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon,
return 0;
}
-static ssize_t qlcnic_store_beacon(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static int qlcnic_83xx_store_beacon(struct qlcnic_adapter *adapter,
+ const char *buf, size_t len)
{
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
struct qlcnic_hardware_context *ahw = adapter->ahw;
- int err, max_sds_rings = adapter->max_sds_rings;
- u16 beacon;
- u8 b_state, b_rate;
unsigned long h_beacon;
+ int err;
- if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
- dev_warn(dev,
- "LED test not supported in non privileged mode\n");
- return -EOPNOTSUPP;
- }
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EIO;
- if (qlcnic_83xx_check(adapter) &&
- !test_bit(__QLCNIC_RESETTING, &adapter->state)) {
- if (kstrtoul(buf, 2, &h_beacon))
- return -EINVAL;
+ if (kstrtoul(buf, 2, &h_beacon))
+ return -EINVAL;
- if (ahw->beacon_state == h_beacon)
- return len;
+ if (ahw->beacon_state == h_beacon)
+ return len;
- rtnl_lock();
- if (!ahw->beacon_state) {
- if (test_and_set_bit(__QLCNIC_LED_ENABLE,
- &adapter->state)) {
- rtnl_unlock();
- return -EBUSY;
- }
- }
- if (h_beacon) {
- err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
- if (err)
- goto beacon_err;
- } else {
- err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
- if (err)
- goto beacon_err;
+ rtnl_lock();
+ if (!ahw->beacon_state) {
+ if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
+ rtnl_unlock();
+ return -EBUSY;
}
- /* set the current beacon state */
+ }
+
+ if (h_beacon)
+ err = qlcnic_83xx_config_led(adapter, 1, h_beacon);
+ else
+ err = qlcnic_83xx_config_led(adapter, 0, !h_beacon);
+ if (!err)
ahw->beacon_state = h_beacon;
-beacon_err:
- if (!ahw->beacon_state)
- clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
- rtnl_unlock();
- return len;
- }
+ if (!ahw->beacon_state)
+ clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+
+ rtnl_unlock();
+ return len;
+}
+
+static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,
+ const char *buf, size_t len)
+{
+ struct qlcnic_hardware_context *ahw = adapter->ahw;
+ int err, max_sds_rings = adapter->max_sds_rings;
+ u16 beacon;
+ u8 h_beacon_state, b_state, b_rate;
if (len != sizeof(u16))
return QL_STATUS_INVALID_PARAM;
@@ -174,16 +168,29 @@ beacon_err:
if (err)
return err;
- if (adapter->ahw->beacon_state == b_state)
+ if ((ahw->capabilities2 & QLCNIC_FW_CAPABILITY_2_BEACON)) {
+ err = qlcnic_get_beacon_state(adapter, &h_beacon_state);
+ if (!err) {
+ dev_info(&adapter->pdev->dev,
+ "Failed to get current beacon state\n");
+ } else {
+ if (h_beacon_state == QLCNIC_BEACON_DISABLE)
+ ahw->beacon_state = 0;
+ else if (h_beacon_state == QLCNIC_BEACON_EANBLE)
+ ahw->beacon_state = 2;
+ }
+ }
+
+ if (ahw->beacon_state == b_state)
return len;
rtnl_lock();
-
- if (!adapter->ahw->beacon_state)
+ if (!ahw->beacon_state) {
if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
rtnl_unlock();
return -EBUSY;
}
+ }
if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
err = -EIO;
@@ -206,14 +213,37 @@ beacon_err:
if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
- out:
- if (!adapter->ahw->beacon_state)
+out:
+ if (!ahw->beacon_state)
clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
rtnl_unlock();
return err;
}
+static ssize_t qlcnic_store_beacon(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int err = 0;
+
+ if (adapter->ahw->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ dev_warn(dev,
+ "LED test not supported in non privileged mode\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (qlcnic_82xx_check(adapter))
+ err = qlcnic_82xx_store_beacon(adapter, buf, len);
+ else if (qlcnic_83xx_check(adapter))
+ err = qlcnic_83xx_store_beacon(adapter, buf, len);
+ else
+ return -EIO;
+
+ return err;
+}
+
static ssize_t qlcnic_show_beacon(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -544,6 +574,9 @@ static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
switch (esw_cfg[i].op_mode) {
case QLCNIC_PORT_DEFAULTS:
qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
+ rtnl_lock();
+ qlcnic_set_netdev_features(adapter, &esw_cfg[i]);
+ rtnl_unlock();
break;
case QLCNIC_ADD_VLAN:
qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index 87463bc..2553cf45 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -1106,6 +1106,7 @@ static int ql_get_next_chunk(struct ql_adapter *qdev, struct rx_ring *rx_ring,
if (pci_dma_mapping_error(qdev->pdev, map)) {
__free_pages(rx_ring->pg_chunk.page,
qdev->lbq_buf_order);
+ rx_ring->pg_chunk.page = NULL;
netif_err(qdev, drv, qdev->ndev,
"PCI mapping failed.\n");
return -ENOMEM;
@@ -2777,6 +2778,12 @@ static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
curr_idx = 0;
}
+ if (rx_ring->pg_chunk.page) {
+ pci_unmap_page(qdev->pdev, rx_ring->pg_chunk.map,
+ ql_lbq_block_size(qdev), PCI_DMA_FROMDEVICE);
+ put_page(rx_ring->pg_chunk.page);
+ rx_ring->pg_chunk.page = NULL;
+ }
}
static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
@@ -4710,6 +4717,7 @@ static int qlge_probe(struct pci_dev *pdev,
dev_err(&pdev->dev, "net device registration failed.\n");
ql_release_all(pdev);
pci_disable_device(pdev);
+ free_netdev(ndev);
return err;
}
/* Start up the timer to trigger EEH if
@@ -4938,15 +4946,4 @@ static struct pci_driver qlge_driver = {
.err_handler = &qlge_err_handler
};
-static int __init qlge_init_module(void)
-{
- return pci_register_driver(&qlge_driver);
-}
-
-static void __exit qlge_exit(void)
-{
- pci_unregister_driver(&qlge_driver);
-}
-
-module_init(qlge_init_module);
-module_exit(qlge_exit);
+module_pci_driver(qlge_driver);
diff --git a/drivers/net/ethernet/rdc/Kconfig b/drivers/net/ethernet/rdc/Kconfig
index c8ba4b3..2055f7e 100644
--- a/drivers/net/ethernet/rdc/Kconfig
+++ b/drivers/net/ethernet/rdc/Kconfig
@@ -22,7 +22,6 @@ config R6040
tristate "RDC R6040 Fast Ethernet Adapter support"
depends on PCI
select CRC32
- select NET_CORE
select MII
select PHYLIB
---help---
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 7d1fb9a..0352345 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -1136,6 +1136,7 @@ static void cp_clean_rings (struct cp_private *cp)
cp->dev->stats.tx_dropped++;
}
}
+ netdev_reset_queue(cp->dev);
memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
index 783fa8b..ae5d027 100644
--- a/drivers/net/ethernet/realtek/Kconfig
+++ b/drivers/net/ethernet/realtek/Kconfig
@@ -37,7 +37,6 @@ config 8139CP
tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This is a driver for the Fast Ethernet PCI network cards based on
@@ -52,7 +51,6 @@ config 8139TOO
tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This is a driver for the Fast Ethernet PCI network cards based on
@@ -107,7 +105,6 @@ config R8169
depends on PCI
select FW_LOADER
select CRC32
- select NET_CORE
select MII
---help---
Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 79c520b..393f961 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -5856,7 +5856,20 @@ err_out:
return -EIO;
}
-static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
+static bool rtl_skb_pad(struct sk_buff *skb)
+{
+ if (skb_padto(skb, ETH_ZLEN))
+ return false;
+ skb_put(skb, ETH_ZLEN - skb->len);
+ return true;
+}
+
+static bool rtl_test_hw_pad_bug(struct rtl8169_private *tp, struct sk_buff *skb)
+{
+ return skb->len < ETH_ZLEN && tp->mac_version == RTL_GIGA_MAC_VER_34;
+}
+
+static inline bool rtl8169_tso_csum(struct rtl8169_private *tp,
struct sk_buff *skb, u32 *opts)
{
const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version;
@@ -5869,13 +5882,20 @@ static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
const struct iphdr *ip = ip_hdr(skb);
+ if (unlikely(rtl_test_hw_pad_bug(tp, skb)))
+ return skb_checksum_help(skb) == 0 && rtl_skb_pad(skb);
+
if (ip->protocol == IPPROTO_TCP)
opts[offset] |= info->checksum.tcp;
else if (ip->protocol == IPPROTO_UDP)
opts[offset] |= info->checksum.udp;
else
WARN_ON_ONCE(1);
+ } else {
+ if (unlikely(rtl_test_hw_pad_bug(tp, skb)))
+ return rtl_skb_pad(skb);
}
+ return true;
}
static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
@@ -5896,17 +5916,15 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
goto err_stop_0;
}
- /* 8168evl does not automatically pad to minimum length. */
- if (unlikely(tp->mac_version == RTL_GIGA_MAC_VER_34 &&
- skb->len < ETH_ZLEN)) {
- if (skb_padto(skb, ETH_ZLEN))
- goto err_update_stats;
- skb_put(skb, ETH_ZLEN - skb->len);
- }
-
if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
goto err_stop_0;
+ opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb));
+ opts[0] = DescOwn;
+
+ if (!rtl8169_tso_csum(tp, skb, opts))
+ goto err_update_stats;
+
len = skb_headlen(skb);
mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(d, mapping))) {
@@ -5918,11 +5936,6 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
tp->tx_skb[entry].len = len;
txd->addr = cpu_to_le64(mapping);
- opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb));
- opts[0] = DescOwn;
-
- rtl8169_tso_csum(tp, skb, opts);
-
frags = rtl8169_xmit_frags(tp, skb, opts);
if (frags < 0)
goto err_dma_1;
diff --git a/drivers/net/ethernet/renesas/Kconfig b/drivers/net/ethernet/renesas/Kconfig
index bed9841..544514e 100644
--- a/drivers/net/ethernet/renesas/Kconfig
+++ b/drivers/net/ethernet/renesas/Kconfig
@@ -4,14 +4,7 @@
config SH_ETH
tristate "Renesas SuperH Ethernet support"
- depends on (SUPERH || ARCH_SHMOBILE) && \
- (CPU_SUBTYPE_SH7710 || CPU_SUBTYPE_SH7712 || \
- CPU_SUBTYPE_SH7763 || CPU_SUBTYPE_SH7619 || \
- CPU_SUBTYPE_SH7724 || CPU_SUBTYPE_SH7734 || \
- CPU_SUBTYPE_SH7757 || ARCH_R8A7740 || \
- ARCH_R8A7778 || ARCH_R8A7779)
select CRC32
- select NET_CORE
select MII
select MDIO_BITBANG
select PHYLIB
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 33dc6f2..7732f11 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -313,9 +313,14 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
[TSU_ADRL31] = 0x01fc,
};
-#if defined(CONFIG_CPU_SUBTYPE_SH7734) || \
- defined(CONFIG_CPU_SUBTYPE_SH7763) || \
- defined(CONFIG_ARCH_R8A7740)
+static int sh_eth_is_gether(struct sh_eth_private *mdp)
+{
+ if (mdp->reg_offset == sh_eth_offset_gigabit)
+ return 1;
+ else
+ return 0;
+}
+
static void sh_eth_select_mii(struct net_device *ndev)
{
u32 value = 0x0;
@@ -339,11 +344,7 @@ static void sh_eth_select_mii(struct net_device *ndev)
sh_eth_write(ndev, value, RMII_MII);
}
-#endif
-/* There is CPU dependent code */
-#if defined(CONFIG_ARCH_R8A7778) || defined(CONFIG_ARCH_R8A7779)
-#define SH_ETH_RESET_DEFAULT 1
static void sh_eth_set_duplex(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -354,7 +355,8 @@ static void sh_eth_set_duplex(struct net_device *ndev)
sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
}
-static void sh_eth_set_rate(struct net_device *ndev)
+/* There is CPU dependent code */
+static void sh_eth_set_rate_r8a777x(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -371,9 +373,9 @@ static void sh_eth_set_rate(struct net_device *ndev)
}
/* R8A7778/9 */
-static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+static struct sh_eth_cpu_data r8a777x_data = {
.set_duplex = sh_eth_set_duplex,
- .set_rate = sh_eth_set_rate,
+ .set_rate = sh_eth_set_rate_r8a777x,
.ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
.ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
@@ -382,26 +384,14 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
.eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
- .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
.apr = 1,
.mpr = 1,
.tpauser = 1,
.hw_swap = 1,
};
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-#define SH_ETH_RESET_DEFAULT 1
-static void sh_eth_set_duplex(struct net_device *ndev)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
-
- if (mdp->duplex) /* Full */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
- else /* Half */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
-}
-static void sh_eth_set_rate(struct net_device *ndev)
+static void sh_eth_set_rate_sh7724(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -418,18 +408,17 @@ static void sh_eth_set_rate(struct net_device *ndev)
}
/* SH7724 */
-static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+static struct sh_eth_cpu_data sh7724_data = {
.set_duplex = sh_eth_set_duplex,
- .set_rate = sh_eth_set_rate,
+ .set_rate = sh_eth_set_rate_sh7724,
.ecsr_value = ECSR_PSRTO | ECSR_LCHNG | ECSR_ICD,
.ecsipr_value = ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | ECSIPR_ICDIP,
- .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x01ff009f,
+ .eesipr_value = 0x01ff009f,
.tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
.eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
- .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
.apr = 1,
.mpr = 1,
@@ -438,22 +427,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.rpadir = 1,
.rpadir_value = 0x00020000, /* NET_IP_ALIGN assumed to be 2 */
};
-#elif defined(CONFIG_CPU_SUBTYPE_SH7757)
-#define SH_ETH_HAS_BOTH_MODULES 1
-#define SH_ETH_HAS_TSU 1
-static int sh_eth_check_reset(struct net_device *ndev);
-static void sh_eth_set_duplex(struct net_device *ndev)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
-
- if (mdp->duplex) /* Full */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
- else /* Half */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
-}
-
-static void sh_eth_set_rate(struct net_device *ndev)
+static void sh_eth_set_rate_sh7757(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -470,9 +445,9 @@ static void sh_eth_set_rate(struct net_device *ndev)
}
/* SH7757 */
-static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
- .set_duplex = sh_eth_set_duplex,
- .set_rate = sh_eth_set_rate,
+static struct sh_eth_cpu_data sh7757_data = {
+ .set_duplex = sh_eth_set_duplex,
+ .set_rate = sh_eth_set_rate_sh7757,
.eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
.rmcr_value = 0x00000001,
@@ -480,8 +455,8 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.tx_check = EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | EESR_RTO,
.eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE |
EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI,
- .tx_error_check = EESR_TWB | EESR_TABT | EESR_TDE | EESR_TFE,
+ .irq_flags = IRQF_SHARED,
.apr = 1,
.mpr = 1,
.tpauser = 1,
@@ -491,7 +466,7 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.rpadir_value = 2 << 16,
};
-#define SH_GIGA_ETH_BASE 0xfee00000
+#define SH_GIGA_ETH_BASE 0xfee00000UL
#define GIGA_MALR(port) (SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c8)
#define GIGA_MAHR(port) (SH_GIGA_ETH_BASE + 0x800 * (port) + 0x05c0)
static void sh_eth_chip_reset_giga(struct net_device *ndev)
@@ -516,52 +491,6 @@ static void sh_eth_chip_reset_giga(struct net_device *ndev)
}
}
-static int sh_eth_is_gether(struct sh_eth_private *mdp);
-static int sh_eth_reset(struct net_device *ndev)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
- int ret = 0;
-
- if (sh_eth_is_gether(mdp)) {
- sh_eth_write(ndev, 0x03, EDSR);
- sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER,
- EDMR);
-
- ret = sh_eth_check_reset(ndev);
- if (ret)
- goto out;
-
- /* Table Init */
- sh_eth_write(ndev, 0x0, TDLAR);
- sh_eth_write(ndev, 0x0, TDFAR);
- sh_eth_write(ndev, 0x0, TDFXR);
- sh_eth_write(ndev, 0x0, TDFFR);
- sh_eth_write(ndev, 0x0, RDLAR);
- sh_eth_write(ndev, 0x0, RDFAR);
- sh_eth_write(ndev, 0x0, RDFXR);
- sh_eth_write(ndev, 0x0, RDFFR);
- } else {
- sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_ETHER,
- EDMR);
- mdelay(3);
- sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER,
- EDMR);
- }
-
-out:
- return ret;
-}
-
-static void sh_eth_set_duplex_giga(struct net_device *ndev)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
-
- if (mdp->duplex) /* Full */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
- else /* Half */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
-}
-
static void sh_eth_set_rate_giga(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -582,9 +511,9 @@ static void sh_eth_set_rate_giga(struct net_device *ndev)
}
/* SH7757(GETHERC) */
-static struct sh_eth_cpu_data sh_eth_my_cpu_data_giga = {
+static struct sh_eth_cpu_data sh7757_data_giga = {
.chip_reset = sh_eth_chip_reset_giga,
- .set_duplex = sh_eth_set_duplex_giga,
+ .set_duplex = sh_eth_set_duplex,
.set_rate = sh_eth_set_rate_giga,
.ecsr_value = ECSR_ICD | ECSR_MPD,
@@ -595,11 +524,10 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data_giga = {
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
EESR_ECI,
- .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
- EESR_TFE,
.fdr_value = 0x0000072f,
.rmcr_value = 0x00000001,
+ .irq_flags = IRQF_SHARED,
.apr = 1,
.mpr = 1,
.tpauser = 1,
@@ -612,19 +540,6 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data_giga = {
.tsu = 1,
};
-static struct sh_eth_cpu_data *sh_eth_get_cpu_data(struct sh_eth_private *mdp)
-{
- if (sh_eth_is_gether(mdp))
- return &sh_eth_my_cpu_data_giga;
- else
- return &sh_eth_my_cpu_data;
-}
-
-#elif defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763)
-#define SH_ETH_HAS_TSU 1
-static int sh_eth_check_reset(struct net_device *ndev);
-static void sh_eth_reset_hw_crc(struct net_device *ndev);
-
static void sh_eth_chip_reset(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -634,17 +549,7 @@ static void sh_eth_chip_reset(struct net_device *ndev)
mdelay(1);
}
-static void sh_eth_set_duplex(struct net_device *ndev)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
-
- if (mdp->duplex) /* Full */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
- else /* Half */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
-}
-
-static void sh_eth_set_rate(struct net_device *ndev)
+static void sh_eth_set_rate_gether(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -663,11 +568,11 @@ static void sh_eth_set_rate(struct net_device *ndev)
}
}
-/* sh7763 */
-static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+/* SH7734 */
+static struct sh_eth_cpu_data sh7734_data = {
.chip_reset = sh_eth_chip_reset,
.set_duplex = sh_eth_set_duplex,
- .set_rate = sh_eth_set_rate,
+ .set_rate = sh_eth_set_rate_gether,
.ecsr_value = ECSR_ICD | ECSR_MPD,
.ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
@@ -677,8 +582,6 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
EESR_ECI,
- .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
- EESR_TFE,
.apr = 1,
.mpr = 1,
@@ -688,54 +591,37 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.no_trimd = 1,
.no_ade = 1,
.tsu = 1,
-#if defined(CONFIG_CPU_SUBTYPE_SH7734)
- .hw_crc = 1,
- .select_mii = 1,
-#endif
+ .hw_crc = 1,
+ .select_mii = 1,
};
-static int sh_eth_reset(struct net_device *ndev)
-{
- int ret = 0;
-
- sh_eth_write(ndev, EDSR_ENALL, EDSR);
- sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR);
-
- ret = sh_eth_check_reset(ndev);
- if (ret)
- goto out;
+/* SH7763 */
+static struct sh_eth_cpu_data sh7763_data = {
+ .chip_reset = sh_eth_chip_reset,
+ .set_duplex = sh_eth_set_duplex,
+ .set_rate = sh_eth_set_rate_gether,
- /* Table Init */
- sh_eth_write(ndev, 0x0, TDLAR);
- sh_eth_write(ndev, 0x0, TDFAR);
- sh_eth_write(ndev, 0x0, TDFXR);
- sh_eth_write(ndev, 0x0, TDFFR);
- sh_eth_write(ndev, 0x0, RDLAR);
- sh_eth_write(ndev, 0x0, RDFAR);
- sh_eth_write(ndev, 0x0, RDFXR);
- sh_eth_write(ndev, 0x0, RDFFR);
-
- /* Reset HW CRC register */
- sh_eth_reset_hw_crc(ndev);
-
- /* Select MII mode */
- if (sh_eth_my_cpu_data.select_mii)
- sh_eth_select_mii(ndev);
-out:
- return ret;
-}
+ .ecsr_value = ECSR_ICD | ECSR_MPD,
+ .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
-static void sh_eth_reset_hw_crc(struct net_device *ndev)
-{
- if (sh_eth_my_cpu_data.hw_crc)
- sh_eth_write(ndev, 0x0, CSMR);
-}
+ .tx_check = EESR_TC1 | EESR_FTC,
+ .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
+ EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
+ EESR_ECI,
-#elif defined(CONFIG_ARCH_R8A7740)
-#define SH_ETH_HAS_TSU 1
-static int sh_eth_check_reset(struct net_device *ndev);
+ .apr = 1,
+ .mpr = 1,
+ .tpauser = 1,
+ .bculr = 1,
+ .hw_swap = 1,
+ .no_trimd = 1,
+ .no_ade = 1,
+ .tsu = 1,
+ .irq_flags = IRQF_SHARED,
+};
-static void sh_eth_chip_reset(struct net_device *ndev)
+static void sh_eth_chip_reset_r8a7740(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -746,65 +632,11 @@ static void sh_eth_chip_reset(struct net_device *ndev)
sh_eth_select_mii(ndev);
}
-static int sh_eth_reset(struct net_device *ndev)
-{
- int ret = 0;
-
- sh_eth_write(ndev, EDSR_ENALL, EDSR);
- sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER, EDMR);
-
- ret = sh_eth_check_reset(ndev);
- if (ret)
- goto out;
-
- /* Table Init */
- sh_eth_write(ndev, 0x0, TDLAR);
- sh_eth_write(ndev, 0x0, TDFAR);
- sh_eth_write(ndev, 0x0, TDFXR);
- sh_eth_write(ndev, 0x0, TDFFR);
- sh_eth_write(ndev, 0x0, RDLAR);
- sh_eth_write(ndev, 0x0, RDFAR);
- sh_eth_write(ndev, 0x0, RDFXR);
- sh_eth_write(ndev, 0x0, RDFFR);
-
-out:
- return ret;
-}
-
-static void sh_eth_set_duplex(struct net_device *ndev)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
-
- if (mdp->duplex) /* Full */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) | ECMR_DM, ECMR);
- else /* Half */
- sh_eth_write(ndev, sh_eth_read(ndev, ECMR) & ~ECMR_DM, ECMR);
-}
-
-static void sh_eth_set_rate(struct net_device *ndev)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
-
- switch (mdp->speed) {
- case 10: /* 10BASE */
- sh_eth_write(ndev, GECMR_10, GECMR);
- break;
- case 100:/* 100BASE */
- sh_eth_write(ndev, GECMR_100, GECMR);
- break;
- case 1000: /* 1000BASE */
- sh_eth_write(ndev, GECMR_1000, GECMR);
- break;
- default:
- break;
- }
-}
-
/* R8A7740 */
-static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
- .chip_reset = sh_eth_chip_reset,
+static struct sh_eth_cpu_data r8a7740_data = {
+ .chip_reset = sh_eth_chip_reset_r8a7740,
.set_duplex = sh_eth_set_duplex,
- .set_rate = sh_eth_set_rate,
+ .set_rate = sh_eth_set_rate_gether,
.ecsr_value = ECSR_ICD | ECSR_MPD,
.ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
@@ -814,8 +646,6 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | \
EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE | \
EESR_ECI,
- .tx_error_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_TDE | \
- EESR_TFE,
.apr = 1,
.mpr = 1,
@@ -826,11 +656,10 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.no_ade = 1,
.tsu = 1,
.select_mii = 1,
+ .shift_rd0 = 1,
};
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
-#define SH_ETH_RESET_DEFAULT 1
-static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+static struct sh_eth_cpu_data sh7619_data = {
.eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
.apr = 1,
@@ -838,14 +667,11 @@ static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
.tpauser = 1,
.hw_swap = 1,
};
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
-#define SH_ETH_RESET_DEFAULT 1
-#define SH_ETH_HAS_TSU 1
-static struct sh_eth_cpu_data sh_eth_my_cpu_data = {
+
+static struct sh_eth_cpu_data sh771x_data = {
.eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
.tsu = 1,
};
-#endif
static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
{
@@ -870,22 +696,8 @@ static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
if (!cd->eesr_err_check)
cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK;
-
- if (!cd->tx_error_check)
- cd->tx_error_check = DEFAULT_TX_ERROR_CHECK;
}
-#if defined(SH_ETH_RESET_DEFAULT)
-/* Chip Reset */
-static int sh_eth_reset(struct net_device *ndev)
-{
- sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_ETHER, EDMR);
- mdelay(3);
- sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER, EDMR);
-
- return 0;
-}
-#else
static int sh_eth_check_reset(struct net_device *ndev)
{
int ret = 0;
@@ -897,13 +709,55 @@ static int sh_eth_check_reset(struct net_device *ndev)
mdelay(1);
cnt--;
}
- if (cnt < 0) {
- pr_err("Device reset fail\n");
+ if (cnt <= 0) {
+ pr_err("Device reset failed\n");
ret = -ETIMEDOUT;
}
return ret;
}
-#endif
+
+static int sh_eth_reset(struct net_device *ndev)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ int ret = 0;
+
+ if (sh_eth_is_gether(mdp)) {
+ sh_eth_write(ndev, EDSR_ENALL, EDSR);
+ sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_GETHER,
+ EDMR);
+
+ ret = sh_eth_check_reset(ndev);
+ if (ret)
+ goto out;
+
+ /* Table Init */
+ sh_eth_write(ndev, 0x0, TDLAR);
+ sh_eth_write(ndev, 0x0, TDFAR);
+ sh_eth_write(ndev, 0x0, TDFXR);
+ sh_eth_write(ndev, 0x0, TDFFR);
+ sh_eth_write(ndev, 0x0, RDLAR);
+ sh_eth_write(ndev, 0x0, RDFAR);
+ sh_eth_write(ndev, 0x0, RDFXR);
+ sh_eth_write(ndev, 0x0, RDFFR);
+
+ /* Reset HW CRC register */
+ if (mdp->cd->hw_crc)
+ sh_eth_write(ndev, 0x0, CSMR);
+
+ /* Select MII mode */
+ if (mdp->cd->select_mii)
+ sh_eth_select_mii(ndev);
+ } else {
+ sh_eth_write(ndev, sh_eth_read(ndev, EDMR) | EDMR_SRST_ETHER,
+ EDMR);
+ mdelay(3);
+ sh_eth_write(ndev, sh_eth_read(ndev, EDMR) & ~EDMR_SRST_ETHER,
+ EDMR);
+ }
+
+out:
+ return ret;
+}
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
static void sh_eth_set_receive_align(struct sk_buff *skb)
@@ -979,14 +833,6 @@ static void read_mac_address(struct net_device *ndev, unsigned char *mac)
}
}
-static int sh_eth_is_gether(struct sh_eth_private *mdp)
-{
- if (mdp->reg_offset == sh_eth_offset_gigabit)
- return 1;
- else
- return 0;
-}
-
static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
{
if (sh_eth_is_gether(mdp))
@@ -1385,7 +1231,7 @@ static int sh_eth_txfree(struct net_device *ndev)
}
/* Packet receive function */
-static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
+static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
struct sh_eth_rxdesc *rxdesc;
@@ -1393,6 +1239,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
int entry = mdp->cur_rx % mdp->num_rx_ring;
int boguscnt = (mdp->dirty_rx + mdp->num_rx_ring) - mdp->cur_rx;
struct sk_buff *skb;
+ int exceeded = 0;
u16 pkt_len = 0;
u32 desc_status;
@@ -1401,16 +1248,28 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
desc_status = edmac_to_cpu(mdp, rxdesc->status);
pkt_len = rxdesc->frame_length;
-#if defined(CONFIG_ARCH_R8A7740)
- desc_status >>= 16;
-#endif
-
if (--boguscnt < 0)
break;
+ if (*quota <= 0) {
+ exceeded = 1;
+ break;
+ }
+ (*quota)--;
+
if (!(desc_status & RDFEND))
ndev->stats.rx_length_errors++;
+ /*
+ * In case of almost all GETHER/ETHERs, the Receive Frame State
+ * (RFS) bits in the Receive Descriptor 0 are from bit 9 to
+ * bit 0. However, in case of the R8A7740's GETHER, the RFS
+ * bits are from bit 25 to bit 16. So, the driver needs right
+ * shifting by 16.
+ */
+ if (mdp->cd->shift_rd0)
+ desc_status >>= 16;
+
if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 |
RD_RFS5 | RD_RFS6 | RD_RFS10)) {
ndev->stats.rx_errors++;
@@ -1484,7 +1343,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status)
sh_eth_write(ndev, EDRRR_R, EDRRR);
}
- return 0;
+ return exceeded;
}
static void sh_eth_rcv_snd_disable(struct net_device *ndev)
@@ -1625,7 +1484,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
struct sh_eth_private *mdp = netdev_priv(ndev);
struct sh_eth_cpu_data *cd = mdp->cd;
irqreturn_t ret = IRQ_NONE;
- unsigned long intr_status;
+ unsigned long intr_status, intr_enable;
spin_lock(&mdp->lock);
@@ -1636,34 +1495,41 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
* and we need to fully handle it in sh_eth_error() in order to quench
* it as it doesn't get cleared by just writing 1 to the ECI bit...
*/
- intr_status &= sh_eth_read(ndev, EESIPR) | DMAC_M_ECI;
- /* Clear interrupt */
- if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF |
- EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF |
- cd->tx_check | cd->eesr_err_check)) {
- sh_eth_write(ndev, intr_status, EESR);
+ intr_enable = sh_eth_read(ndev, EESIPR);
+ intr_status &= intr_enable | DMAC_M_ECI;
+ if (intr_status & (EESR_RX_CHECK | cd->tx_check | cd->eesr_err_check))
ret = IRQ_HANDLED;
- } else
+ else
goto other_irq;
- if (intr_status & (EESR_FRC | /* Frame recv*/
- EESR_RMAF | /* Multi cast address recv*/
- EESR_RRF | /* Bit frame recv */
- EESR_RTLF | /* Long frame recv*/
- EESR_RTSF | /* short frame recv */
- EESR_PRE | /* PHY-LSI recv error */
- EESR_CERF)){ /* recv frame CRC error */
- sh_eth_rx(ndev, intr_status);
+ if (intr_status & EESR_RX_CHECK) {
+ if (napi_schedule_prep(&mdp->napi)) {
+ /* Mask Rx interrupts */
+ sh_eth_write(ndev, intr_enable & ~EESR_RX_CHECK,
+ EESIPR);
+ __napi_schedule(&mdp->napi);
+ } else {
+ dev_warn(&ndev->dev,
+ "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
+ intr_status, intr_enable);
+ }
}
/* Tx Check */
if (intr_status & cd->tx_check) {
+ /* Clear Tx interrupts */
+ sh_eth_write(ndev, intr_status & cd->tx_check, EESR);
+
sh_eth_txfree(ndev);
netif_wake_queue(ndev);
}
- if (intr_status & cd->eesr_err_check)
+ if (intr_status & cd->eesr_err_check) {
+ /* Clear error interrupts */
+ sh_eth_write(ndev, intr_status & cd->eesr_err_check, EESR);
+
sh_eth_error(ndev, intr_status);
+ }
other_irq:
spin_unlock(&mdp->lock);
@@ -1671,6 +1537,33 @@ other_irq:
return ret;
}
+static int sh_eth_poll(struct napi_struct *napi, int budget)
+{
+ struct sh_eth_private *mdp = container_of(napi, struct sh_eth_private,
+ napi);
+ struct net_device *ndev = napi->dev;
+ int quota = budget;
+ unsigned long intr_status;
+
+ for (;;) {
+ intr_status = sh_eth_read(ndev, EESR);
+ if (!(intr_status & EESR_RX_CHECK))
+ break;
+ /* Clear Rx interrupts */
+ sh_eth_write(ndev, intr_status & EESR_RX_CHECK, EESR);
+
+ if (sh_eth_rx(ndev, intr_status, &quota))
+ goto out;
+ }
+
+ napi_complete(napi);
+
+ /* Reenable Rx interrupts */
+ sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
+out:
+ return budget - quota;
+}
+
/* PHY state control function */
static void sh_eth_adjust_link(struct net_device *ndev)
{
@@ -1961,14 +1854,7 @@ static int sh_eth_open(struct net_device *ndev)
pm_runtime_get_sync(&mdp->pdev->dev);
ret = request_irq(ndev->irq, sh_eth_interrupt,
-#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \
- defined(CONFIG_CPU_SUBTYPE_SH7764) || \
- defined(CONFIG_CPU_SUBTYPE_SH7757)
- IRQF_SHARED,
-#else
- 0,
-#endif
- ndev->name, ndev);
+ mdp->cd->irq_flags, ndev->name, ndev);
if (ret) {
dev_err(&ndev->dev, "Can not assign IRQ number\n");
return ret;
@@ -1989,6 +1875,8 @@ static int sh_eth_open(struct net_device *ndev)
if (ret)
goto out_free_irq;
+ napi_enable(&mdp->napi);
+
return ret;
out_free_irq:
@@ -2084,6 +1972,8 @@ static int sh_eth_close(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
+ napi_disable(&mdp->napi);
+
netif_stop_queue(ndev);
/* Disable interrupts by clearing the interrupt mask. */
@@ -2154,7 +2044,6 @@ static int sh_eth_do_ioctl(struct net_device *ndev, struct ifreq *rq,
return phy_mii_ioctl(phydev, rq, cmd);
}
-#if defined(SH_ETH_HAS_TSU)
/* For TSU_POSTn. Please refer to the manual about this (strange) bitfields */
static void *sh_eth_tsu_get_post_reg_offset(struct sh_eth_private *mdp,
int entry)
@@ -2497,7 +2386,6 @@ static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev,
return 0;
}
-#endif /* SH_ETH_HAS_TSU */
/* SuperH's TSU register init function */
static void sh_eth_tsu_init(struct sh_eth_private *mdp)
@@ -2641,11 +2529,21 @@ static const struct net_device_ops sh_eth_netdev_ops = {
.ndo_stop = sh_eth_close,
.ndo_start_xmit = sh_eth_start_xmit,
.ndo_get_stats = sh_eth_get_stats,
-#if defined(SH_ETH_HAS_TSU)
+ .ndo_tx_timeout = sh_eth_tx_timeout,
+ .ndo_do_ioctl = sh_eth_do_ioctl,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static const struct net_device_ops sh_eth_netdev_ops_tsu = {
+ .ndo_open = sh_eth_open,
+ .ndo_stop = sh_eth_close,
+ .ndo_start_xmit = sh_eth_start_xmit,
+ .ndo_get_stats = sh_eth_get_stats,
.ndo_set_rx_mode = sh_eth_set_multicast_list,
.ndo_vlan_rx_add_vid = sh_eth_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = sh_eth_vlan_rx_kill_vid,
-#endif
.ndo_tx_timeout = sh_eth_tx_timeout,
.ndo_do_ioctl = sh_eth_do_ioctl,
.ndo_validate_addr = eth_validate_addr,
@@ -2660,6 +2558,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
struct net_device *ndev = NULL;
struct sh_eth_private *mdp = NULL;
struct sh_eth_plat_data *pd = pdev->dev.platform_data;
+ const struct platform_device_id *id = platform_get_device_id(pdev);
/* get base addr */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -2718,15 +2617,14 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
mdp->reg_offset = sh_eth_get_register_offset(pd->register_type);
/* set cpu data */
-#if defined(SH_ETH_HAS_BOTH_MODULES)
- mdp->cd = sh_eth_get_cpu_data(mdp);
-#else
- mdp->cd = &sh_eth_my_cpu_data;
-#endif
+ mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
sh_eth_set_default_cpu_data(mdp->cd);
/* set function */
- ndev->netdev_ops = &sh_eth_netdev_ops;
+ if (mdp->cd->tsu)
+ ndev->netdev_ops = &sh_eth_netdev_ops_tsu;
+ else
+ ndev->netdev_ops = &sh_eth_netdev_ops;
SET_ETHTOOL_OPS(ndev, &sh_eth_ethtool_ops);
ndev->watchdog_timeo = TX_TIMEOUT;
@@ -2745,11 +2643,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
if (mdp->cd->tsu) {
struct resource *rtsu;
rtsu = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!rtsu) {
- dev_err(&pdev->dev, "Not found TSU resource\n");
- ret = -ENODEV;
- goto out_release;
- }
mdp->tsu_addr = devm_ioremap_resource(&pdev->dev, rtsu);
if (IS_ERR(mdp->tsu_addr)) {
ret = PTR_ERR(mdp->tsu_addr);
@@ -2770,10 +2663,12 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
}
}
+ netif_napi_add(ndev, &mdp->napi, sh_eth_poll, 64);
+
/* network device register */
ret = register_netdev(ndev);
if (ret)
- goto out_release;
+ goto out_napi_del;
/* mdio bus init */
ret = sh_mdio_init(ndev, pdev->id, pd);
@@ -2791,6 +2686,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
out_unregister:
unregister_netdev(ndev);
+out_napi_del:
+ netif_napi_del(&mdp->napi);
+
out_release:
/* net_dev free */
if (ndev)
@@ -2803,16 +2701,18 @@ out:
static int sh_eth_drv_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
+ struct sh_eth_private *mdp = netdev_priv(ndev);
sh_mdio_release(ndev);
unregister_netdev(ndev);
+ netif_napi_del(&mdp->napi);
pm_runtime_disable(&pdev->dev);
free_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
+#ifdef CONFIG_PM
static int sh_eth_runtime_nop(struct device *dev)
{
/*
@@ -2826,17 +2726,36 @@ static int sh_eth_runtime_nop(struct device *dev)
return 0;
}
-static struct dev_pm_ops sh_eth_dev_pm_ops = {
+static const struct dev_pm_ops sh_eth_dev_pm_ops = {
.runtime_suspend = sh_eth_runtime_nop,
.runtime_resume = sh_eth_runtime_nop,
};
+#define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops)
+#else
+#define SH_ETH_PM_OPS NULL
+#endif
+
+static struct platform_device_id sh_eth_id_table[] = {
+ { "sh7619-ether", (kernel_ulong_t)&sh7619_data },
+ { "sh771x-ether", (kernel_ulong_t)&sh771x_data },
+ { "sh7724-ether", (kernel_ulong_t)&sh7724_data },
+ { "sh7734-gether", (kernel_ulong_t)&sh7734_data },
+ { "sh7757-ether", (kernel_ulong_t)&sh7757_data },
+ { "sh7757-gether", (kernel_ulong_t)&sh7757_data_giga },
+ { "sh7763-gether", (kernel_ulong_t)&sh7763_data },
+ { "r8a7740-gether", (kernel_ulong_t)&r8a7740_data },
+ { "r8a777x-ether", (kernel_ulong_t)&r8a777x_data },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, sh_eth_id_table);
static struct platform_driver sh_eth_driver = {
.probe = sh_eth_drv_probe,
.remove = sh_eth_drv_remove,
+ .id_table = sh_eth_id_table,
.driver = {
.name = CARDNAME,
- .pm = &sh_eth_dev_pm_ops,
+ .pm = SH_ETH_PM_OPS,
},
};
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 1ddc9f2..a78fb0c 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -166,19 +166,16 @@ enum {
/*
* Register's bits
*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7734) || defined(CONFIG_CPU_SUBTYPE_SH7763) ||\
- defined(CONFIG_ARCH_R8A7740)
-/* EDSR */
+/* EDSR : sh7734, sh7757, sh7763, and r8a7740 only */
enum EDSR_BIT {
EDSR_ENT = 0x01, EDSR_ENR = 0x02,
};
#define EDSR_ENALL (EDSR_ENT|EDSR_ENR)
-/* GECMR */
+/* GECMR : sh7734, sh7763 and r8a7740 only */
enum GECMR_BIT {
GECMR_10 = 0x0, GECMR_100 = 0x04, GECMR_1000 = 0x01,
};
-#endif
/* EDMR */
enum DMAC_M_BIT {
@@ -251,13 +248,19 @@ enum EESR_BIT {
EESR_CERF = 0x00000001,
};
+#define EESR_RX_CHECK (EESR_FRC | /* Frame recv */ \
+ EESR_RMAF | /* Multicast address recv */ \
+ EESR_RRF | /* Bit frame recv */ \
+ EESR_RTLF | /* Long frame recv */ \
+ EESR_RTSF | /* Short frame recv */ \
+ EESR_PRE | /* PHY-LSI recv error */ \
+ EESR_CERF) /* Recv frame CRC error */
+
#define DEFAULT_TX_CHECK (EESR_FTC | EESR_CND | EESR_DLC | EESR_CD | \
EESR_RTO)
#define DEFAULT_EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | \
EESR_RDE | EESR_RFRMER | EESR_ADE | \
EESR_TFE | EESR_TDE | EESR_ECI)
-#define DEFAULT_TX_ERROR_CHECK (EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | \
- EESR_TFE)
/* EESIPR */
enum DMAC_IM_BIT {
@@ -299,11 +302,11 @@ enum FCFTR_BIT {
#define DEFAULT_FIFO_F_D_RFF (FCFTR_RFF2 | FCFTR_RFF1 | FCFTR_RFF0)
#define DEFAULT_FIFO_F_D_RFD (FCFTR_RFD2 | FCFTR_RFD1 | FCFTR_RFD0)
-/* Transfer descriptor bit */
+/* Transmit descriptor bit */
enum TD_STS_BIT {
- TD_TACT = 0x80000000,
- TD_TDLE = 0x40000000, TD_TFP1 = 0x20000000,
- TD_TFP0 = 0x10000000,
+ TD_TACT = 0x80000000, TD_TDLE = 0x40000000,
+ TD_TFP1 = 0x20000000, TD_TFP0 = 0x10000000,
+ TD_TFE = 0x08000000, TD_TWBI = 0x04000000,
};
#define TDF1ST TD_TFP1
#define TDFEND TD_TFP0
@@ -463,9 +466,9 @@ struct sh_eth_cpu_data {
/* interrupt checking mask */
unsigned long tx_check;
unsigned long eesr_err_check;
- unsigned long tx_error_check;
/* hardware features */
+ unsigned long irq_flags; /* IRQ configuration flags */
unsigned no_psr:1; /* EtherC DO NOT have PSR */
unsigned apr:1; /* EtherC have APR */
unsigned mpr:1; /* EtherC have MPR */
@@ -478,6 +481,7 @@ struct sh_eth_cpu_data {
unsigned no_ade:1; /* E-DMAC DO NOT have ADE bit in EESR */
unsigned hw_crc:1; /* E-DMAC have CSMR */
unsigned select_mii:1; /* EtherC have RMII_MII (MII select register) */
+ unsigned shift_rd0:1; /* shift Rx descriptor word 0 right by 16 */
};
struct sh_eth_private {
@@ -499,6 +503,7 @@ struct sh_eth_private {
u32 cur_tx, dirty_tx;
u32 rx_buf_sz; /* Based on MTU+slack. */
int edmac_endian;
+ struct napi_struct napi;
/* MII transceiver section. */
u32 phy_id; /* PHY ID */
struct mii_bus *mii_bus; /* MDIO bus control */
diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c
index b6739af..a99739c 100644
--- a/drivers/net/ethernet/s6gmac.c
+++ b/drivers/net/ethernet/s6gmac.c
@@ -1040,7 +1040,6 @@ static int s6gmac_remove(struct platform_device *pdev)
unregister_netdev(dev);
free_irq(dev->irq, dev);
free_netdev(dev);
- platform_set_drvdata(pdev, NULL);
}
return 0;
}
diff --git a/drivers/net/ethernet/seeq/sgiseeq.c b/drivers/net/ethernet/seeq/sgiseeq.c
index 0ad5694..856e523 100644
--- a/drivers/net/ethernet/seeq/sgiseeq.c
+++ b/drivers/net/ethernet/seeq/sgiseeq.c
@@ -818,7 +818,6 @@ static int __exit sgiseeq_remove(struct platform_device *pdev)
dma_free_noncoherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
sp->srings_dma);
free_netdev(dev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 01b9920..46cc11d 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -638,14 +638,16 @@ static void efx_start_datapath(struct efx_nic *efx)
EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
efx->type->rx_buffer_padding);
rx_buf_len = (sizeof(struct efx_rx_page_state) +
- EFX_PAGE_IP_ALIGN + efx->rx_dma_len);
+ NET_IP_ALIGN + efx->rx_dma_len);
if (rx_buf_len <= PAGE_SIZE) {
efx->rx_scatter = false;
efx->rx_buffer_order = 0;
} else if (efx->type->can_rx_scatter) {
+ BUILD_BUG_ON(EFX_RX_USR_BUF_SIZE % L1_CACHE_BYTES);
BUILD_BUG_ON(sizeof(struct efx_rx_page_state) +
- EFX_PAGE_IP_ALIGN + EFX_RX_USR_BUF_SIZE >
- PAGE_SIZE / 2);
+ 2 * ALIGN(NET_IP_ALIGN + EFX_RX_USR_BUF_SIZE,
+ EFX_RX_BUF_ALIGNMENT) >
+ PAGE_SIZE);
efx->rx_scatter = true;
efx->rx_dma_len = EFX_RX_USR_BUF_SIZE;
efx->rx_buffer_order = 0;
@@ -2118,7 +2120,7 @@ static void efx_update_name(struct efx_nic *efx)
static int efx_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct net_device *net_dev = ptr;
+ struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
if (net_dev->netdev_ops == &efx_netdev_ops &&
event == NETDEV_CHANGENAME)
diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h
index 9bd433a..9a2914c 100644
--- a/drivers/net/ethernet/sfc/net_driver.h
+++ b/drivers/net/ethernet/sfc/net_driver.h
@@ -72,8 +72,20 @@
/* Maximum possible MTU the driver supports */
#define EFX_MAX_MTU (9 * 1024)
-/* Size of an RX scatter buffer. Small enough to pack 2 into a 4K page. */
-#define EFX_RX_USR_BUF_SIZE 1824
+/* Size of an RX scatter buffer. Small enough to pack 2 into a 4K page,
+ * and should be a multiple of the cache line size.
+ */
+#define EFX_RX_USR_BUF_SIZE (2048 - 256)
+
+/* If possible, we should ensure cache line alignment at start and end
+ * of every buffer. Otherwise, we just need to ensure 4-byte
+ * alignment of the network header.
+ */
+#if NET_IP_ALIGN == 0
+#define EFX_RX_BUF_ALIGNMENT L1_CACHE_BYTES
+#else
+#define EFX_RX_BUF_ALIGNMENT 4
+#endif
/* Forward declare Precision Time Protocol (PTP) support structure. */
struct efx_ptp_data;
@@ -468,24 +480,11 @@ enum nic_state {
};
/*
- * Alignment of page-allocated RX buffers
- *
- * Controls the number of bytes inserted at the start of an RX buffer.
- * This is the equivalent of NET_IP_ALIGN [which controls the alignment
- * of the skb->head for hardware DMA].
- */
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-#define EFX_PAGE_IP_ALIGN 0
-#else
-#define EFX_PAGE_IP_ALIGN NET_IP_ALIGN
-#endif
-
-/*
* Alignment of the skb->head which wraps a page-allocated RX buffer
*
* The skb allocated to wrap an rx_buffer can have this alignment. Since
* the data is memcpy'd from the rx_buf, it does not need to be equal to
- * EFX_PAGE_IP_ALIGN.
+ * NET_IP_ALIGN.
*/
#define EFX_PAGE_SKB_ALIGN 2
@@ -785,6 +784,7 @@ struct efx_nic {
char name[IFNAMSIZ];
struct pci_dev *pci_dev;
+ unsigned int port_num;
const struct efx_nic_type *type;
int legacy_irq;
bool legacy_irq_enabled;
@@ -917,7 +917,7 @@ static inline int efx_dev_registered(struct efx_nic *efx)
static inline unsigned int efx_port_num(struct efx_nic *efx)
{
- return efx->net_dev->dev_id;
+ return efx->port_num;
}
/**
diff --git a/drivers/net/ethernet/sfc/rx.c b/drivers/net/ethernet/sfc/rx.c
index e73e30b..a7dfe36 100644
--- a/drivers/net/ethernet/sfc/rx.c
+++ b/drivers/net/ethernet/sfc/rx.c
@@ -93,8 +93,8 @@ static inline void efx_sync_rx_buffer(struct efx_nic *efx,
void efx_rx_config_page_split(struct efx_nic *efx)
{
- efx->rx_page_buf_step = ALIGN(efx->rx_dma_len + EFX_PAGE_IP_ALIGN,
- L1_CACHE_BYTES);
+ efx->rx_page_buf_step = ALIGN(efx->rx_dma_len + NET_IP_ALIGN,
+ EFX_RX_BUF_ALIGNMENT);
efx->rx_bufs_per_page = efx->rx_buffer_order ? 1 :
((PAGE_SIZE - sizeof(struct efx_rx_page_state)) /
efx->rx_page_buf_step);
@@ -188,9 +188,9 @@ static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue)
do {
index = rx_queue->added_count & rx_queue->ptr_mask;
rx_buf = efx_rx_buffer(rx_queue, index);
- rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
+ rx_buf->dma_addr = dma_addr + NET_IP_ALIGN;
rx_buf->page = page;
- rx_buf->page_offset = page_offset + EFX_PAGE_IP_ALIGN;
+ rx_buf->page_offset = page_offset + NET_IP_ALIGN;
rx_buf->len = efx->rx_dma_len;
rx_buf->flags = 0;
++rx_queue->added_count;
diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c
index 5166924..8c91775 100644
--- a/drivers/net/ethernet/sfc/siena.c
+++ b/drivers/net/ethernet/sfc/siena.c
@@ -304,7 +304,7 @@ static int siena_probe_nic(struct efx_nic *efx)
}
efx_reado(efx, &reg, FR_AZ_CS_DEBUG);
- efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
+ efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
efx_mcdi_init(efx);
diff --git a/drivers/net/ethernet/sgi/Kconfig b/drivers/net/ethernet/sgi/Kconfig
index c1c4bb8..e832f46 100644
--- a/drivers/net/ethernet/sgi/Kconfig
+++ b/drivers/net/ethernet/sgi/Kconfig
@@ -22,7 +22,6 @@ config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
depends on PCI && SGI_IP27
select CRC32
- select NET_CORE
select MII
---help---
If you have a network (Ethernet) card of this type, say Y and read
diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
index 7ed08c3..ffa7843 100644
--- a/drivers/net/ethernet/sgi/ioc3-eth.c
+++ b/drivers/net/ethernet/sgi/ioc3-eth.c
@@ -1398,16 +1398,6 @@ static struct pci_driver ioc3_driver = {
.remove = ioc3_remove_one,
};
-static int __init ioc3_init_module(void)
-{
- return pci_register_driver(&ioc3_driver);
-}
-
-static void __exit ioc3_cleanup_module(void)
-{
- pci_unregister_driver(&ioc3_driver);
-}
-
static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long data;
@@ -1677,9 +1667,7 @@ static void ioc3_set_multicast_list(struct net_device *dev)
netif_wake_queue(dev); /* Let us get going again. */
}
+module_pci_driver(ioc3_driver);
MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
MODULE_DESCRIPTION("SGI IOC3 Ethernet driver");
MODULE_LICENSE("GPL");
-
-module_init(ioc3_init_module);
-module_exit(ioc3_cleanup_module);
diff --git a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c
index 4bdbaad9..9f5f35e 100644
--- a/drivers/net/ethernet/sgi/meth.c
+++ b/drivers/net/ethernet/sgi/meth.c
@@ -863,7 +863,6 @@ static int __exit meth_remove(struct platform_device *pdev)
unregister_netdev(dev);
free_netdev(dev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/ethernet/silan/sc92031.c b/drivers/net/ethernet/silan/sc92031.c
index 28f7268..5eb933c 100644
--- a/drivers/net/ethernet/silan/sc92031.c
+++ b/drivers/net/ethernet/silan/sc92031.c
@@ -1578,19 +1578,7 @@ static struct pci_driver sc92031_pci_driver = {
.resume = sc92031_resume,
};
-static int __init sc92031_init(void)
-{
- return pci_register_driver(&sc92031_pci_driver);
-}
-
-static void __exit sc92031_exit(void)
-{
- pci_unregister_driver(&sc92031_pci_driver);
-}
-
-module_init(sc92031_init);
-module_exit(sc92031_exit);
-
+module_pci_driver(sc92031_pci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cesar Eduardo Barros <cesarb@cesarb.net>");
MODULE_DESCRIPTION("Silan SC92031 PCI Fast Ethernet Adapter driver");
diff --git a/drivers/net/ethernet/sis/Kconfig b/drivers/net/ethernet/sis/Kconfig
index f1135cc..68d052b 100644
--- a/drivers/net/ethernet/sis/Kconfig
+++ b/drivers/net/ethernet/sis/Kconfig
@@ -22,7 +22,6 @@ config SIS900
tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This is a driver for the Fast Ethernet PCI network cards based on
@@ -39,7 +38,6 @@ config SIS190
tristate "SiS190/SiS191 gigabit ethernet support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or
diff --git a/drivers/net/ethernet/sis/sis190.c b/drivers/net/ethernet/sis/sis190.c
index 9a9c379..02df089 100644
--- a/drivers/net/ethernet/sis/sis190.c
+++ b/drivers/net/ethernet/sis/sis190.c
@@ -1934,15 +1934,4 @@ static struct pci_driver sis190_pci_driver = {
.remove = sis190_remove_one,
};
-static int __init sis190_init_module(void)
-{
- return pci_register_driver(&sis190_pci_driver);
-}
-
-static void __exit sis190_cleanup_module(void)
-{
- pci_unregister_driver(&sis190_pci_driver);
-}
-
-module_init(sis190_init_module);
-module_exit(sis190_cleanup_module);
+module_pci_driver(sis190_pci_driver);
diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index bb4c167..068fc44 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -37,7 +37,6 @@ config SMC9194
config SMC91X
tristate "SMC 91C9x/91C1xxx support"
select CRC32
- select NET_CORE
select MII
depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \
MN10300 || COLDFIRE || ARM64)
@@ -57,7 +56,6 @@ config PCMCIA_SMC91C92
tristate "SMC 91Cxx PCMCIA support"
depends on PCMCIA
select CRC32
- select NET_CORE
select MII
---help---
Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA
@@ -70,7 +68,6 @@ config EPIC100
tristate "SMC EtherPower II"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC,
@@ -81,7 +78,6 @@ config EPIC100
config SMC911X
tristate "SMSC LAN911[5678] support"
select CRC32
- select NET_CORE
select MII
depends on (ARM || SUPERH || MN10300)
---help---
@@ -97,9 +93,8 @@ config SMC911X
config SMSC911X
tristate "SMSC LAN911x/LAN921x families embedded ethernet support"
- depends on (ARM || SUPERH || BLACKFIN || MIPS || MN10300)
+ depends on HAS_IOMEM
select CRC32
- select NET_CORE
select MII
select PHYLIB
---help---
diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c
index 9dd842d..345558f 100644
--- a/drivers/net/ethernet/smsc/smc911x.c
+++ b/drivers/net/ethernet/smsc/smc911x.c
@@ -2087,7 +2087,6 @@ static int smc911x_drv_probe(struct platform_device *pdev)
ndev->base_addr = res->start;
ret = smc911x_probe(ndev);
if (ret != 0) {
- platform_set_drvdata(pdev, NULL);
iounmap(addr);
release_both:
free_netdev(ndev);
@@ -2113,7 +2112,6 @@ static int smc911x_drv_remove(struct platform_device *pdev)
struct resource *res;
DBG(SMC_DEBUG_FUNC, "--> %s\n", __func__);
- platform_set_drvdata(pdev, NULL);
unregister_netdev(ndev);
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index dfbf978..cde13be 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -2299,7 +2299,6 @@ static int smc_drv_probe(struct platform_device *pdev)
return 0;
out_iounmap:
- platform_set_drvdata(pdev, NULL);
iounmap(addr);
out_release_attrib:
smc_release_attrib(pdev, ndev);
@@ -2319,8 +2318,6 @@ static int smc_drv_remove(struct platform_device *pdev)
struct smc_local *lp = netdev_priv(ndev);
struct resource *res;
- platform_set_drvdata(pdev, NULL);
-
unregister_netdev(ndev);
free_irq(ndev->irq, ndev);
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 3663b9e..a1419211 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -2284,7 +2284,6 @@ static int smsc911x_drv_remove(struct platform_device *pdev)
mdiobus_unregister(pdata->mii_bus);
mdiobus_free(pdata->mii_bus);
- platform_set_drvdata(pdev, NULL);
unregister_netdev(dev);
free_irq(dev->irq, dev);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -2539,7 +2538,6 @@ out_disable_resources:
out_enable_resources_fail:
smsc911x_free_resources(pdev);
out_request_resources_fail:
- platform_set_drvdata(pdev, NULL);
iounmap(pdata->ioaddr);
free_netdev(dev);
out_release_io_1:
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index f695a50..6e52c0f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -1,7 +1,6 @@
config STMMAC_ETH
tristate "STMicroelectronics 10/100/1000 Ethernet driver"
- depends on HAS_IOMEM
- select NET_CORE
+ depends on HAS_IOMEM && HAS_DMA
select MII
select PHYLIB
select CRC32
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 618446a..ee919ca 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1899,7 +1899,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
#ifdef STMMAC_XMIT_DEBUG
if (netif_msg_pktdata(priv)) {
- pr_info("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d"
+ pr_info("%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d",
__func__, (priv->cur_tx % txsize),
(priv->dirty_tx % txsize), entry, first, nfrags);
if (priv->extend_desc)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 1d3780f..17bc782 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -171,8 +171,6 @@ static int stmmac_pltfr_remove(struct platform_device *pdev)
if (priv->plat->exit)
priv->plat->exit(pdev);
- platform_set_drvdata(pdev, NULL);
-
return ret;
}
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index 95cff98..fa32240 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -10108,7 +10108,7 @@ static int niu_of_probe(struct platform_device *op)
goto err_out_iounmap;
}
- dev_set_drvdata(&op->dev, dev);
+ platform_set_drvdata(op, dev);
niu_device_announce(np);
@@ -10145,7 +10145,7 @@ err_out:
static int niu_of_remove(struct platform_device *op)
{
- struct net_device *dev = dev_get_drvdata(&op->dev);
+ struct net_device *dev = platform_get_drvdata(op);
if (dev) {
struct niu *np = netdev_priv(dev);
@@ -10175,7 +10175,6 @@ static int niu_of_remove(struct platform_device *op)
niu_put_parent(np);
free_netdev(dev);
- dev_set_drvdata(&op->dev, NULL);
}
return 0;
}
diff --git a/drivers/net/ethernet/sun/sunbmac.c b/drivers/net/ethernet/sun/sunbmac.c
index 0549759..09b4f8c 100644
--- a/drivers/net/ethernet/sun/sunbmac.c
+++ b/drivers/net/ethernet/sun/sunbmac.c
@@ -1017,10 +1017,7 @@ static void bigmac_set_multicast(struct net_device *dev)
tmp |= BIGMAC_RXCFG_PMISC;
sbus_writel(tmp, bregs + BMAC_RXCFG);
} else {
- u16 hash_table[4];
-
- for (i = 0; i < 4; i++)
- hash_table[i] = 0;
+ u16 hash_table[4] = { 0 };
netdev_for_each_mc_addr(ha, dev) {
crc = ether_crc_le(6, ha->addr);
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index 5f3f9d5..e62df2b 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -3028,15 +3028,4 @@ static struct pci_driver gem_driver = {
#endif /* CONFIG_PM */
};
-static int __init gem_init(void)
-{
- return pci_register_driver(&gem_driver);
-}
-
-static void __exit gem_cleanup(void)
-{
- pci_unregister_driver(&gem_driver);
-}
-
-module_init(gem_init);
-module_exit(gem_cleanup);
+module_pci_driver(gem_driver);
diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c
index 436fa9d..171f5b0 100644
--- a/drivers/net/ethernet/sun/sunhme.c
+++ b/drivers/net/ethernet/sun/sunhme.c
@@ -2506,7 +2506,7 @@ static struct quattro *quattro_sbus_find(struct platform_device *child)
struct quattro *qp;
op = to_platform_device(parent);
- qp = dev_get_drvdata(&op->dev);
+ qp = platform_get_drvdata(op);
if (qp)
return qp;
@@ -2521,7 +2521,7 @@ static struct quattro *quattro_sbus_find(struct platform_device *child)
qp->next = qfe_sbus_list;
qfe_sbus_list = qp;
- dev_set_drvdata(&op->dev, qp);
+ platform_set_drvdata(op, qp);
}
return qp;
}
diff --git a/drivers/net/ethernet/sun/sunqe.c b/drivers/net/ethernet/sun/sunqe.c
index 8182591b..b072f4d 100644
--- a/drivers/net/ethernet/sun/sunqe.c
+++ b/drivers/net/ethernet/sun/sunqe.c
@@ -767,7 +767,7 @@ static struct sunqec *get_qec(struct platform_device *child)
struct platform_device *op = to_platform_device(child->dev.parent);
struct sunqec *qecp;
- qecp = dev_get_drvdata(&op->dev);
+ qecp = platform_get_drvdata(op);
if (!qecp) {
qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
if (qecp) {
@@ -801,7 +801,7 @@ static struct sunqec *get_qec(struct platform_device *child)
goto fail;
}
- dev_set_drvdata(&op->dev, qecp);
+ platform_set_drvdata(op, qecp);
qecp->next_module = root_qec_dev;
root_qec_dev = qecp;
@@ -902,7 +902,7 @@ static int qec_ether_init(struct platform_device *op)
if (res)
goto fail;
- dev_set_drvdata(&op->dev, qe);
+ platform_set_drvdata(op, qe);
printk(KERN_INFO "%s: qe channel[%d] %pM\n", dev->name, qe->channel,
dev->dev_addr);
@@ -934,7 +934,7 @@ static int qec_sbus_probe(struct platform_device *op)
static int qec_sbus_remove(struct platform_device *op)
{
- struct sunqe *qp = dev_get_drvdata(&op->dev);
+ struct sunqe *qp = platform_get_drvdata(op);
struct net_device *net_dev = qp->dev;
unregister_netdev(net_dev);
@@ -948,8 +948,6 @@ static int qec_sbus_remove(struct platform_device *op)
free_netdev(net_dev);
- dev_set_drvdata(&op->dev, NULL);
-
return 0;
}
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 21a5b29..101b037 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1554,6 +1554,8 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
if (mac_addr)
memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
+ slave_data->phy_if = of_get_phy_mode(slave_node);
+
if (data->dual_emac) {
if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
&prop)) {
@@ -1679,7 +1681,7 @@ static int cpsw_probe(struct platform_device *pdev)
priv->rx_packet_max = max(rx_packet_max, 128);
priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL);
priv->irq_enabled = true;
- if (!ndev) {
+ if (!priv->cpts) {
pr_err("error allocating cpts\n");
goto clean_ndev_ret;
}
@@ -1940,7 +1942,6 @@ static int cpsw_remove(struct platform_device *pdev)
struct cpsw_priv *priv = netdev_priv(ndev);
int i;
- platform_set_drvdata(pdev, NULL);
if (priv->data.dual_emac)
unregister_netdev(cpsw_get_slave_ndev(priv, 1));
unregister_netdev(ndev);
diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c
index 49dfd592..a377bc7 100644
--- a/drivers/net/ethernet/ti/davinci_cpdma.c
+++ b/drivers/net/ethernet/ti/davinci_cpdma.c
@@ -64,6 +64,7 @@
#define CPDMA_DESC_TO_PORT_EN BIT(20)
#define CPDMA_TO_PORT_SHIFT 16
#define CPDMA_DESC_PORT_MASK (BIT(18) | BIT(17) | BIT(16))
+#define CPDMA_DESC_CRC_LEN 4
#define CPDMA_TEARDOWN_VALUE 0xfffffffc
@@ -798,6 +799,10 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
status = -EBUSY;
goto unlock_ret;
}
+
+ if (status & CPDMA_DESC_PASS_CRC)
+ outlen -= CPDMA_DESC_CRC_LEN;
+
status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE |
CPDMA_DESC_PORT_MASK);
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 860e15d..efb6f65 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -2037,8 +2037,6 @@ static int davinci_emac_remove(struct platform_device *pdev)
dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n");
- platform_set_drvdata(pdev, NULL);
-
if (priv->txchan)
cpdma_chan_destroy(priv->txchan);
if (priv->rxchan)
diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c
index 12aec17..c47f0db 100644
--- a/drivers/net/ethernet/ti/davinci_mdio.c
+++ b/drivers/net/ethernet/ti/davinci_mdio.c
@@ -449,10 +449,9 @@ static int davinci_mdio_suspend(struct device *dev)
__raw_writel(ctrl, &data->regs->control);
wait_for_idle(data);
- pm_runtime_put_sync(data->dev);
-
data->suspended = true;
spin_unlock(&data->lock);
+ pm_runtime_put_sync(data->dev);
return 0;
}
@@ -460,15 +459,12 @@ static int davinci_mdio_suspend(struct device *dev)
static int davinci_mdio_resume(struct device *dev)
{
struct davinci_mdio_data *data = dev_get_drvdata(dev);
- u32 ctrl;
- spin_lock(&data->lock);
pm_runtime_get_sync(data->dev);
+ spin_lock(&data->lock);
/* restart the scan state machine */
- ctrl = __raw_readl(&data->regs->control);
- ctrl |= CONTROL_ENABLE;
- __raw_writel(ctrl, &data->regs->control);
+ __davinci_mdio_reset(data);
data->suspended = false;
spin_unlock(&data->lock);
@@ -477,8 +473,8 @@ static int davinci_mdio_resume(struct device *dev)
}
static const struct dev_pm_ops davinci_mdio_pm_ops = {
- .suspend = davinci_mdio_suspend,
- .resume = davinci_mdio_resume,
+ .suspend_late = davinci_mdio_suspend,
+ .resume_early = davinci_mdio_resume,
};
static const struct of_device_id davinci_mdio_of_mtable[] = {
diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c
index 60c400f..59abfbc 100644
--- a/drivers/net/ethernet/ti/tlan.c
+++ b/drivers/net/ethernet/ti/tlan.c
@@ -533,7 +533,6 @@ static int tlan_probe1(struct pci_dev *pdev, long ioaddr, int irq, int rev,
/* This is a hack. We need to know which board structure
* is suited for this adapter */
device_id = inw(ioaddr + EISA_ID2);
- priv->is_eisa = 1;
if (device_id == 0x20F1) {
priv->adapter = &board_info[13]; /* NetFlex-3/E */
priv->adapter_rev = 23; /* TLAN 2.3 */
diff --git a/drivers/net/ethernet/ti/tlan.h b/drivers/net/ethernet/ti/tlan.h
index 5fc98a8..2eb33a2 100644
--- a/drivers/net/ethernet/ti/tlan.h
+++ b/drivers/net/ethernet/ti/tlan.h
@@ -207,7 +207,6 @@ struct tlan_priv {
u8 tlan_full_duplex;
spinlock_t lock;
u8 link;
- u8 is_eisa;
struct work_struct tlan_tqueue;
u8 neg_be_verbose;
};
diff --git a/drivers/net/ethernet/toshiba/tc35815.c b/drivers/net/ethernet/toshiba/tc35815.c
index fe25609..a971b9c 100644
--- a/drivers/net/ethernet/toshiba/tc35815.c
+++ b/drivers/net/ethernet/toshiba/tc35815.c
@@ -2209,18 +2209,6 @@ MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
module_param_named(duplex, options.duplex, int, 0);
MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
-static int __init tc35815_init_module(void)
-{
- return pci_register_driver(&tc35815_pci_driver);
-}
-
-static void __exit tc35815_cleanup_module(void)
-{
- pci_unregister_driver(&tc35815_pci_driver);
-}
-
-module_init(tc35815_init_module);
-module_exit(tc35815_cleanup_module);
-
+module_pci_driver(tc35815_pci_driver);
MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/tundra/tsi108_eth.c b/drivers/net/ethernet/tundra/tsi108_eth.c
index 3c69a04..01bdc6c 100644
--- a/drivers/net/ethernet/tundra/tsi108_eth.c
+++ b/drivers/net/ethernet/tundra/tsi108_eth.c
@@ -1682,7 +1682,6 @@ static int tsi108_ether_remove(struct platform_device *pdev)
unregister_netdev(dev);
tsi108_stop_ethernet(dev);
- platform_set_drvdata(pdev, NULL);
iounmap(priv->regs);
iounmap(priv->phyregs);
free_netdev(dev);
diff --git a/drivers/net/ethernet/via/Kconfig b/drivers/net/ethernet/via/Kconfig
index 68a9ba6..8a049a2 100644
--- a/drivers/net/ethernet/via/Kconfig
+++ b/drivers/net/ethernet/via/Kconfig
@@ -5,7 +5,6 @@
config NET_VENDOR_VIA
bool "VIA devices"
default y
- depends on PCI
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -22,7 +21,6 @@ config VIA_RHINE
tristate "VIA Rhine support"
depends on PCI
select CRC32
- select NET_CORE
select MII
---help---
If you have a VIA "Rhine" based network card (Rhine-I (VT86C100A),
@@ -45,10 +43,9 @@ config VIA_RHINE_MMIO
config VIA_VELOCITY
tristate "VIA Velocity support"
- depends on PCI
+ depends on (PCI || USE_OF)
select CRC32
select CRC_CCITT
- select NET_CORE
select MII
---help---
If you have a VIA "Velocity" based network card say Y here.
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index fb62489..7691994 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -46,6 +46,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/init.h>
+#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ioport.h>
@@ -64,7 +65,11 @@
#include <linux/if.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/inetdevice.h>
+#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
@@ -79,10 +84,24 @@
#include "via-velocity.h"
+enum velocity_bus_type {
+ BUS_PCI,
+ BUS_PLATFORM,
+};
static int velocity_nics;
static int msglevel = MSG_LEVEL_INFO;
+static void velocity_set_power_state(struct velocity_info *vptr, char state)
+{
+ void *addr = vptr->mac_regs;
+
+ if (vptr->pdev)
+ pci_set_power_state(vptr->pdev, state);
+ else
+ writeb(state, addr + 0x154);
+}
+
/**
* mac_get_cam_mask - Read a CAM mask
* @regs: register block for this velocity
@@ -361,12 +380,23 @@ static struct velocity_info_tbl chip_info_table[] = {
* Describe the PCI device identifiers that we support in this
* device driver. Used for hotplug autoloading.
*/
-static DEFINE_PCI_DEVICE_TABLE(velocity_id_table) = {
+
+static DEFINE_PCI_DEVICE_TABLE(velocity_pci_id_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
{ }
};
-MODULE_DEVICE_TABLE(pci, velocity_id_table);
+MODULE_DEVICE_TABLE(pci, velocity_pci_id_table);
+
+/**
+ * Describe the OF device identifiers that we support in this
+ * device driver. Used for devicetree nodes.
+ */
+static struct of_device_id velocity_of_ids[] = {
+ { .compatible = "via,velocity-vt6110", .data = &chip_info_table[0] },
+ { /* Sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, velocity_of_ids);
/**
* get_chip_name - identifier to name
@@ -385,29 +415,6 @@ static const char *get_chip_name(enum chip_type chip_id)
}
/**
- * velocity_remove1 - device unplug
- * @pdev: PCI device being removed
- *
- * Device unload callback. Called on an unplug or on module
- * unload for each active device that is present. Disconnects
- * the device from the network layer and frees all the resources
- */
-static void velocity_remove1(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
-
- unregister_netdev(dev);
- iounmap(vptr->mac_regs);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
- free_netdev(dev);
-
- velocity_nics--;
-}
-
-/**
* velocity_set_int_opt - parser for integer options
* @opt: pointer to option value
* @val: value the user requested (or -1 for default)
@@ -998,9 +1005,9 @@ static void velocity_print_link_status(struct velocity_info *vptr)
{
if (vptr->mii_status & VELOCITY_LINK_FAIL) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->netdev->name);
} else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->netdev->name);
if (vptr->mii_status & VELOCITY_SPEED_1000)
VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
@@ -1014,7 +1021,7 @@ static void velocity_print_link_status(struct velocity_info *vptr)
else
VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
} else {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->netdev->name);
switch (vptr->options.spd_dpx) {
case SPD_DPX_1000_FULL:
VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps full duplex\n");
@@ -1180,6 +1187,17 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
u16 BMCR;
switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+ case PHYID_ICPLUS_IP101A:
+ MII_REG_BITS_ON((ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP),
+ MII_ADVERTISE, vptr->mac_regs);
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ MII_REG_BITS_ON(TCSR_ECHODIS, MII_SREVISION,
+ vptr->mac_regs);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_SREVISION,
+ vptr->mac_regs);
+ MII_REG_BITS_ON(PLED_LALBE, MII_TPISTATUS, vptr->mac_regs);
+ break;
case PHYID_CICADA_CS8201:
/*
* Reset to hardware default
@@ -1311,6 +1329,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
enum velocity_init_type type)
{
struct mac_regs __iomem *regs = vptr->mac_regs;
+ struct net_device *netdev = vptr->netdev;
int i, mii_status;
mac_wol_reset(regs);
@@ -1319,7 +1338,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
case VELOCITY_INIT_RESET:
case VELOCITY_INIT_WOL:
- netif_stop_queue(vptr->dev);
+ netif_stop_queue(netdev);
/*
* Reset RX to prevent RX pointer not on the 4X location
@@ -1332,7 +1351,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
velocity_print_link_status(vptr);
if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
- netif_wake_queue(vptr->dev);
+ netif_wake_queue(netdev);
}
enable_flow_control_ability(vptr);
@@ -1352,9 +1371,11 @@ static void velocity_init_registers(struct velocity_info *vptr,
velocity_soft_reset(vptr);
mdelay(5);
- mac_eeprom_reload(regs);
- for (i = 0; i < 6; i++)
- writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
+ if (!vptr->no_eeprom) {
+ mac_eeprom_reload(regs);
+ for (i = 0; i < 6; i++)
+ writeb(netdev->dev_addr[i], regs->PAR + i);
+ }
/*
* clear Pre_ACPI bit.
@@ -1377,7 +1398,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
/*
* Set packet filter: Receive directed and broadcast address
*/
- velocity_set_multi(vptr->dev);
+ velocity_set_multi(netdev);
/*
* Enable MII auto-polling
@@ -1404,14 +1425,14 @@ static void velocity_init_registers(struct velocity_info *vptr,
writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT), &regs->CR0Set);
mii_status = velocity_get_opt_media_mode(vptr);
- netif_stop_queue(vptr->dev);
+ netif_stop_queue(netdev);
mii_init(vptr, mii_status);
if (velocity_set_media_mode(vptr, mii_status) != VELOCITY_LINK_CHANGE) {
velocity_print_link_status(vptr);
if (!(vptr->mii_status & VELOCITY_LINK_FAIL))
- netif_wake_queue(vptr->dev);
+ netif_wake_queue(netdev);
}
enable_flow_control_ability(vptr);
@@ -1459,7 +1480,6 @@ static int velocity_init_dma_rings(struct velocity_info *vptr)
struct velocity_opt *opt = &vptr->options;
const unsigned int rx_ring_size = opt->numrx * sizeof(struct rx_desc);
const unsigned int tx_ring_size = opt->numtx * sizeof(struct tx_desc);
- struct pci_dev *pdev = vptr->pdev;
dma_addr_t pool_dma;
void *pool;
unsigned int i;
@@ -1467,14 +1487,14 @@ static int velocity_init_dma_rings(struct velocity_info *vptr)
/*
* Allocate all RD/TD rings a single pool.
*
- * pci_alloc_consistent() fulfills the requirement for 64 bytes
+ * dma_alloc_coherent() fulfills the requirement for 64 bytes
* alignment
*/
- pool = pci_alloc_consistent(pdev, tx_ring_size * vptr->tx.numq +
- rx_ring_size, &pool_dma);
+ pool = dma_alloc_coherent(vptr->dev, tx_ring_size * vptr->tx.numq +
+ rx_ring_size, &pool_dma, GFP_ATOMIC);
if (!pool) {
- dev_err(&pdev->dev, "%s : DMA memory allocation failed.\n",
- vptr->dev->name);
+ dev_err(vptr->dev, "%s : DMA memory allocation failed.\n",
+ vptr->netdev->name);
return -ENOMEM;
}
@@ -1514,7 +1534,7 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
struct rx_desc *rd = &(vptr->rx.ring[idx]);
struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
- rd_info->skb = netdev_alloc_skb(vptr->dev, vptr->rx.buf_sz + 64);
+ rd_info->skb = netdev_alloc_skb(vptr->netdev, vptr->rx.buf_sz + 64);
if (rd_info->skb == NULL)
return -ENOMEM;
@@ -1524,8 +1544,8 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
*/
skb_reserve(rd_info->skb,
64 - ((unsigned long) rd_info->skb->data & 63));
- rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data,
- vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
+ rd_info->skb_dma = dma_map_single(vptr->dev, rd_info->skb->data,
+ vptr->rx.buf_sz, DMA_FROM_DEVICE);
/*
* Fill in the descriptor to match
@@ -1588,8 +1608,8 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
if (!rd_info->skb)
continue;
- pci_unmap_single(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_single(vptr->dev, rd_info->skb_dma, vptr->rx.buf_sz,
+ DMA_FROM_DEVICE);
rd_info->skb_dma = 0;
dev_kfree_skb(rd_info->skb);
@@ -1620,7 +1640,7 @@ static int velocity_init_rd_ring(struct velocity_info *vptr)
if (velocity_rx_refill(vptr) != vptr->options.numrx) {
VELOCITY_PRT(MSG_LEVEL_ERR, KERN_ERR
- "%s: failed to allocate RX buffer.\n", vptr->dev->name);
+ "%s: failed to allocate RX buffer.\n", vptr->netdev->name);
velocity_free_rd_ring(vptr);
goto out;
}
@@ -1670,7 +1690,7 @@ static void velocity_free_dma_rings(struct velocity_info *vptr)
const int size = vptr->options.numrx * sizeof(struct rx_desc) +
vptr->options.numtx * sizeof(struct tx_desc) * vptr->tx.numq;
- pci_free_consistent(vptr->pdev, size, vptr->rx.ring, vptr->rx.pool_dma);
+ dma_free_coherent(vptr->dev, size, vptr->rx.ring, vptr->rx.pool_dma);
}
static int velocity_init_rings(struct velocity_info *vptr, int mtu)
@@ -1727,8 +1747,8 @@ static void velocity_free_tx_buf(struct velocity_info *vptr,
pktlen = max_t(size_t, pktlen,
td->td_buf[i].size & ~TD_QUEUE);
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i],
- le16_to_cpu(pktlen), PCI_DMA_TODEVICE);
+ dma_unmap_single(vptr->dev, tdinfo->skb_dma[i],
+ le16_to_cpu(pktlen), DMA_TO_DEVICE);
}
}
dev_kfree_skb_irq(skb);
@@ -1750,8 +1770,8 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr,
if (td_info->skb) {
for (i = 0; i < td_info->nskb_dma; i++) {
if (td_info->skb_dma[i]) {
- pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
- td_info->skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(vptr->dev, td_info->skb_dma[i],
+ td_info->skb->len, DMA_TO_DEVICE);
td_info->skb_dma[i] = 0;
}
}
@@ -1809,7 +1829,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
writew(TRDCSR_RUN, &regs->TDCSRClr);
- netif_stop_queue(vptr->dev);
+ netif_stop_queue(vptr->netdev);
/* FIXME: port over the pci_device_failed code and use it
here */
@@ -1850,10 +1870,10 @@ static void velocity_error(struct velocity_info *vptr, int status)
if (linked) {
vptr->mii_status &= ~VELOCITY_LINK_FAIL;
- netif_carrier_on(vptr->dev);
+ netif_carrier_on(vptr->netdev);
} else {
vptr->mii_status |= VELOCITY_LINK_FAIL;
- netif_carrier_off(vptr->dev);
+ netif_carrier_off(vptr->netdev);
}
velocity_print_link_status(vptr);
@@ -1867,9 +1887,9 @@ static void velocity_error(struct velocity_info *vptr, int status)
enable_mii_autopoll(regs);
if (vptr->mii_status & VELOCITY_LINK_FAIL)
- netif_stop_queue(vptr->dev);
+ netif_stop_queue(vptr->netdev);
else
- netif_wake_queue(vptr->dev);
+ netif_wake_queue(vptr->netdev);
}
if (status & ISR_MIBFI)
@@ -1894,7 +1914,7 @@ static int velocity_tx_srv(struct velocity_info *vptr)
int idx;
int works = 0;
struct velocity_td_info *tdinfo;
- struct net_device_stats *stats = &vptr->dev->stats;
+ struct net_device_stats *stats = &vptr->netdev->stats;
for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
@@ -1939,9 +1959,9 @@ static int velocity_tx_srv(struct velocity_info *vptr)
* Look to see if we should kick the transmit network
* layer for more work.
*/
- if (netif_queue_stopped(vptr->dev) && (full == 0) &&
+ if (netif_queue_stopped(vptr->netdev) && (full == 0) &&
(!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
- netif_wake_queue(vptr->dev);
+ netif_wake_queue(vptr->netdev);
}
return works;
}
@@ -1989,7 +2009,7 @@ static int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
if (pkt_size < rx_copybreak) {
struct sk_buff *new_skb;
- new_skb = netdev_alloc_skb_ip_align(vptr->dev, pkt_size);
+ new_skb = netdev_alloc_skb_ip_align(vptr->netdev, pkt_size);
if (new_skb) {
new_skb->ip_summed = rx_skb[0]->ip_summed;
skb_copy_from_linear_data(*rx_skb, new_skb->data, pkt_size);
@@ -2029,15 +2049,14 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
*/
static int velocity_receive_frame(struct velocity_info *vptr, int idx)
{
- void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
- struct net_device_stats *stats = &vptr->dev->stats;
+ struct net_device_stats *stats = &vptr->netdev->stats;
struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
struct rx_desc *rd = &(vptr->rx.ring[idx]);
int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
struct sk_buff *skb;
if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
- VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->dev->name);
+ VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame span multple RDs.\n", vptr->netdev->name);
stats->rx_length_errors++;
return -EINVAL;
}
@@ -2047,8 +2066,8 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
skb = rd_info->skb;
- pci_dma_sync_single_for_cpu(vptr->pdev, rd_info->skb_dma,
- vptr->rx.buf_sz, PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(vptr->dev, rd_info->skb_dma,
+ vptr->rx.buf_sz, DMA_FROM_DEVICE);
/*
* Drop frame not meeting IEEE 802.3
@@ -2061,21 +2080,20 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
}
}
- pci_action = pci_dma_sync_single_for_device;
-
velocity_rx_csum(rd, skb);
if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) {
velocity_iph_realign(vptr, skb, pkt_len);
- pci_action = pci_unmap_single;
rd_info->skb = NULL;
+ dma_unmap_single(vptr->dev, rd_info->skb_dma, vptr->rx.buf_sz,
+ DMA_FROM_DEVICE);
+ } else {
+ dma_sync_single_for_device(vptr->dev, rd_info->skb_dma,
+ vptr->rx.buf_sz, DMA_FROM_DEVICE);
}
- pci_action(vptr->pdev, rd_info->skb_dma, vptr->rx.buf_sz,
- PCI_DMA_FROMDEVICE);
-
skb_put(skb, pkt_len - 4);
- skb->protocol = eth_type_trans(skb, vptr->dev);
+ skb->protocol = eth_type_trans(skb, vptr->netdev);
if (rd->rdesc0.RSR & RSR_DETAG) {
u16 vid = swab16(le16_to_cpu(rd->rdesc1.PQTAG));
@@ -2100,7 +2118,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
*/
static int velocity_rx_srv(struct velocity_info *vptr, int budget_left)
{
- struct net_device_stats *stats = &vptr->dev->stats;
+ struct net_device_stats *stats = &vptr->netdev->stats;
int rd_curr = vptr->rx.curr;
int works = 0;
@@ -2235,15 +2253,15 @@ static int velocity_open(struct net_device *dev)
goto out;
/* Ensure chip is running */
- pci_set_power_state(vptr->pdev, PCI_D0);
+ velocity_set_power_state(vptr, PCI_D0);
velocity_init_registers(vptr, VELOCITY_INIT_COLD);
- ret = request_irq(vptr->pdev->irq, velocity_intr, IRQF_SHARED,
+ ret = request_irq(dev->irq, velocity_intr, IRQF_SHARED,
dev->name, dev);
if (ret < 0) {
/* Power down the chip */
- pci_set_power_state(vptr->pdev, PCI_D3hot);
+ velocity_set_power_state(vptr, PCI_D3hot);
velocity_free_rings(vptr);
goto out;
}
@@ -2292,7 +2310,7 @@ static int velocity_change_mtu(struct net_device *dev, int new_mtu)
if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) {
VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n",
- vptr->dev->name);
+ vptr->netdev->name);
ret = -EINVAL;
goto out_0;
}
@@ -2314,8 +2332,9 @@ static int velocity_change_mtu(struct net_device *dev, int new_mtu)
goto out_0;
}
- tmp_vptr->dev = dev;
+ tmp_vptr->netdev = dev;
tmp_vptr->pdev = vptr->pdev;
+ tmp_vptr->dev = vptr->dev;
tmp_vptr->options = vptr->options;
tmp_vptr->tx.numq = vptr->tx.numq;
@@ -2415,7 +2434,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
saving then we need to bring the device back up to talk to it */
if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D0);
+ velocity_set_power_state(vptr, PCI_D0);
switch (cmd) {
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
@@ -2428,7 +2447,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
ret = -EOPNOTSUPP;
}
if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D3hot);
+ velocity_set_power_state(vptr, PCI_D3hot);
return ret;
@@ -2494,7 +2513,7 @@ static int velocity_close(struct net_device *dev)
if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED)
velocity_get_ip(vptr);
- free_irq(vptr->pdev->irq, dev);
+ free_irq(dev->irq, dev);
velocity_free_rings(vptr);
@@ -2550,7 +2569,8 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
* add it to the transmit ring.
*/
tdinfo->skb = skb;
- tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
+ tdinfo->skb_dma[0] = dma_map_single(vptr->dev, skb->data, pktlen,
+ DMA_TO_DEVICE);
td_ptr->tdesc0.len = cpu_to_le16(pktlen);
td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
td_ptr->td_buf[0].pa_high = 0;
@@ -2560,7 +2580,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- tdinfo->skb_dma[i + 1] = skb_frag_dma_map(&vptr->pdev->dev,
+ tdinfo->skb_dma[i + 1] = skb_frag_dma_map(vptr->dev,
frag, 0,
skb_frag_size(frag),
DMA_TO_DEVICE);
@@ -2632,12 +2652,9 @@ static const struct net_device_ops velocity_netdev_ops = {
* Set up the initial velocity_info struct for the device that has been
* discovered.
*/
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
- const struct velocity_info_tbl *info)
+static void velocity_init_info(struct velocity_info *vptr,
+ const struct velocity_info_tbl *info)
{
- memset(vptr, 0, sizeof(struct velocity_info));
-
- vptr->pdev = pdev;
vptr->chip_id = info->chip_id;
vptr->tx.numq = info->txqueue;
vptr->multicast_limit = MCAM_SIZE;
@@ -2652,10 +2669,9 @@ static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
* Retrieve the PCI configuration space data that interests us from
* the kernel PCI layer
*/
-static int velocity_get_pci_info(struct velocity_info *vptr,
- struct pci_dev *pdev)
+static int velocity_get_pci_info(struct velocity_info *vptr)
{
- vptr->rev_id = pdev->revision;
+ struct pci_dev *pdev = vptr->pdev;
pci_set_master(pdev);
@@ -2678,7 +2694,37 @@ static int velocity_get_pci_info(struct velocity_info *vptr,
dev_err(&pdev->dev, "region #1 is too small.\n");
return -EINVAL;
}
- vptr->pdev = pdev;
+
+ return 0;
+}
+
+/**
+ * velocity_get_platform_info - retrieve platform info for device
+ * @vptr: velocity device
+ * @pdev: platform device it matches
+ *
+ * Retrieve the Platform configuration data that interests us
+ */
+static int velocity_get_platform_info(struct velocity_info *vptr)
+{
+ struct resource res;
+ int ret;
+
+ if (of_get_property(vptr->dev->of_node, "no-eeprom", NULL))
+ vptr->no_eeprom = 1;
+
+ ret = of_address_to_resource(vptr->dev->of_node, 0, &res);
+ if (ret) {
+ dev_err(vptr->dev, "unable to find memory address\n");
+ return ret;
+ }
+
+ vptr->memaddr = res.start;
+
+ if (resource_size(&res) < VELOCITY_IO_SIZE) {
+ dev_err(vptr->dev, "memory region is too small.\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -2692,7 +2738,7 @@ static int velocity_get_pci_info(struct velocity_info *vptr,
*/
static void velocity_print_info(struct velocity_info *vptr)
{
- struct net_device *dev = vptr->dev;
+ struct net_device *dev = vptr->netdev;
printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
printk(KERN_INFO "%s: Ethernet Address: %pM\n",
@@ -2707,21 +2753,22 @@ static u32 velocity_get_link(struct net_device *dev)
}
/**
- * velocity_found1 - set up discovered velocity card
+ * velocity_probe - set up discovered velocity device
* @pdev: PCI device
* @ent: PCI device table entry that matched
+ * @bustype: bus that device is connected to
*
* Configure a discovered adapter from scratch. Return a negative
* errno error code on failure paths.
*/
-static int velocity_found1(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int velocity_probe(struct device *dev, int irq,
+ const struct velocity_info_tbl *info,
+ enum velocity_bus_type bustype)
{
static int first = 1;
- struct net_device *dev;
+ struct net_device *netdev;
int i;
const char *drv_string;
- const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
struct velocity_info *vptr;
struct mac_regs __iomem *regs;
int ret = -ENOMEM;
@@ -2730,20 +2777,18 @@ static int velocity_found1(struct pci_dev *pdev,
* can support more than MAX_UNITS.
*/
if (velocity_nics >= MAX_UNITS) {
- dev_notice(&pdev->dev, "already found %d NICs.\n",
- velocity_nics);
+ dev_notice(dev, "already found %d NICs.\n", velocity_nics);
return -ENODEV;
}
- dev = alloc_etherdev(sizeof(struct velocity_info));
- if (!dev)
+ netdev = alloc_etherdev(sizeof(struct velocity_info));
+ if (!netdev)
goto out;
/* Chain it all together */
- SET_NETDEV_DEV(dev, &pdev->dev);
- vptr = netdev_priv(dev);
-
+ SET_NETDEV_DEV(netdev, dev);
+ vptr = netdev_priv(netdev);
if (first) {
printk(KERN_INFO "%s Ver. %s\n",
@@ -2753,41 +2798,41 @@ static int velocity_found1(struct pci_dev *pdev,
first = 0;
}
- velocity_init_info(pdev, vptr, info);
-
+ netdev->irq = irq;
+ vptr->netdev = netdev;
vptr->dev = dev;
- ret = pci_enable_device(pdev);
- if (ret < 0)
- goto err_free_dev;
+ velocity_init_info(vptr, info);
- ret = velocity_get_pci_info(vptr, pdev);
- if (ret < 0) {
- /* error message already printed */
- goto err_disable;
- }
+ if (bustype == BUS_PCI) {
+ vptr->pdev = to_pci_dev(dev);
- ret = pci_request_regions(pdev, VELOCITY_NAME);
- if (ret < 0) {
- dev_err(&pdev->dev, "No PCI resources.\n");
- goto err_disable;
+ ret = velocity_get_pci_info(vptr);
+ if (ret < 0)
+ goto err_free_dev;
+ } else {
+ vptr->pdev = NULL;
+ ret = velocity_get_platform_info(vptr);
+ if (ret < 0)
+ goto err_free_dev;
}
regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
if (regs == NULL) {
ret = -EIO;
- goto err_release_res;
+ goto err_free_dev;
}
vptr->mac_regs = regs;
+ vptr->rev_id = readb(&regs->rev_id);
mac_wol_reset(regs);
for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(&regs->PAR[i]);
+ netdev->dev_addr[i] = readb(&regs->PAR[i]);
- drv_string = dev_driver_string(&pdev->dev);
+ drv_string = dev_driver_string(dev);
velocity_get_options(&vptr->options, velocity_nics, drv_string);
@@ -2808,46 +2853,125 @@ static int velocity_found1(struct pci_dev *pdev,
vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
- dev->netdev_ops = &velocity_netdev_ops;
- dev->ethtool_ops = &velocity_ethtool_ops;
- netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
+ netdev->netdev_ops = &velocity_netdev_ops;
+ netdev->ethtool_ops = &velocity_ethtool_ops;
+ netif_napi_add(netdev, &vptr->napi, velocity_poll,
+ VELOCITY_NAPI_WEIGHT);
- dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
+ netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
NETIF_F_HW_VLAN_CTAG_TX;
- dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_FILTER |
- NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_IP_CSUM;
+ netdev->features |= NETIF_F_HW_VLAN_CTAG_TX |
+ NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_IP_CSUM;
- ret = register_netdev(dev);
+ ret = register_netdev(netdev);
if (ret < 0)
goto err_iounmap;
- if (!velocity_get_link(dev)) {
- netif_carrier_off(dev);
+ if (!velocity_get_link(netdev)) {
+ netif_carrier_off(netdev);
vptr->mii_status |= VELOCITY_LINK_FAIL;
}
velocity_print_info(vptr);
- pci_set_drvdata(pdev, dev);
+ dev_set_drvdata(vptr->dev, netdev);
/* and leave the chip powered down */
- pci_set_power_state(pdev, PCI_D3hot);
+ velocity_set_power_state(vptr, PCI_D3hot);
velocity_nics++;
out:
return ret;
err_iounmap:
iounmap(regs);
-err_release_res:
- pci_release_regions(pdev);
-err_disable:
- pci_disable_device(pdev);
err_free_dev:
- free_netdev(dev);
+ free_netdev(netdev);
goto out;
}
-#ifdef CONFIG_PM
+/**
+ * velocity_remove - device unplug
+ * @dev: device being removed
+ *
+ * Device unload callback. Called on an unplug or on module
+ * unload for each active device that is present. Disconnects
+ * the device from the network layer and frees all the resources
+ */
+static int velocity_remove(struct device *dev)
+{
+ struct net_device *netdev = dev_get_drvdata(dev);
+ struct velocity_info *vptr = netdev_priv(netdev);
+
+ unregister_netdev(netdev);
+ iounmap(vptr->mac_regs);
+ free_netdev(netdev);
+ velocity_nics--;
+
+ return 0;
+}
+
+static int velocity_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ const struct velocity_info_tbl *info =
+ &chip_info_table[ent->driver_data];
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ return ret;
+
+ ret = pci_request_regions(pdev, VELOCITY_NAME);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "No PCI resources.\n");
+ goto fail1;
+ }
+
+ ret = velocity_probe(&pdev->dev, pdev->irq, info, BUS_PCI);
+ if (ret == 0)
+ return 0;
+
+ pci_release_regions(pdev);
+fail1:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void velocity_pci_remove(struct pci_dev *pdev)
+{
+ velocity_remove(&pdev->dev);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static int velocity_platform_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id;
+ const struct velocity_info_tbl *info;
+ int irq;
+
+ of_id = of_match_device(velocity_of_ids, &pdev->dev);
+ if (!of_id)
+ return -EINVAL;
+ info = of_id->data;
+
+ irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ if (!irq)
+ return -EINVAL;
+
+ return velocity_probe(&pdev->dev, irq, info, BUS_PLATFORM);
+}
+
+static int velocity_platform_remove(struct platform_device *pdev)
+{
+ velocity_remove(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
/**
* wol_calc_crc - WOL CRC
* @pattern: data pattern
@@ -3004,32 +3128,35 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co
}
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
+static int velocity_suspend(struct device *dev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
+ struct net_device *netdev = dev_get_drvdata(dev);
+ struct velocity_info *vptr = netdev_priv(netdev);
unsigned long flags;
- if (!netif_running(vptr->dev))
+ if (!netif_running(vptr->netdev))
return 0;
- netif_device_detach(vptr->dev);
+ netif_device_detach(vptr->netdev);
spin_lock_irqsave(&vptr->lock, flags);
- pci_save_state(pdev);
+ if (vptr->pdev)
+ pci_save_state(vptr->pdev);
if (vptr->flags & VELOCITY_FLAGS_WOL_ENABLED) {
velocity_get_ip(vptr);
velocity_save_context(vptr, &vptr->context);
velocity_shutdown(vptr);
velocity_set_wol(vptr);
- pci_enable_wake(pdev, PCI_D3hot, 1);
- pci_set_power_state(pdev, PCI_D3hot);
+ if (vptr->pdev)
+ pci_enable_wake(vptr->pdev, PCI_D3hot, 1);
+ velocity_set_power_state(vptr, PCI_D3hot);
} else {
velocity_save_context(vptr, &vptr->context);
velocity_shutdown(vptr);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ if (vptr->pdev)
+ pci_disable_device(vptr->pdev);
+ velocity_set_power_state(vptr, PCI_D3hot);
}
spin_unlock_irqrestore(&vptr->lock, flags);
@@ -3071,19 +3198,22 @@ static void velocity_restore_context(struct velocity_info *vptr, struct velocity
writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
}
-static int velocity_resume(struct pci_dev *pdev)
+static int velocity_resume(struct device *dev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
+ struct net_device *netdev = dev_get_drvdata(dev);
+ struct velocity_info *vptr = netdev_priv(netdev);
unsigned long flags;
int i;
- if (!netif_running(vptr->dev))
+ if (!netif_running(vptr->netdev))
return 0;
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_wake(pdev, 0, 0);
- pci_restore_state(pdev);
+ velocity_set_power_state(vptr, PCI_D0);
+
+ if (vptr->pdev) {
+ pci_enable_wake(vptr->pdev, 0, 0);
+ pci_restore_state(vptr->pdev);
+ }
mac_wol_reset(vptr->mac_regs);
@@ -3101,27 +3231,38 @@ static int velocity_resume(struct pci_dev *pdev)
mac_enable_int(vptr->mac_regs);
spin_unlock_irqrestore(&vptr->lock, flags);
- netif_device_attach(vptr->dev);
+ netif_device_attach(vptr->netdev);
return 0;
}
-#endif
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(velocity_pm_ops, velocity_suspend, velocity_resume);
/*
* Definition for our device driver. The PCI layer interface
* uses this to handle all our card discover and plugging
*/
-static struct pci_driver velocity_driver = {
+static struct pci_driver velocity_pci_driver = {
.name = VELOCITY_NAME,
- .id_table = velocity_id_table,
- .probe = velocity_found1,
- .remove = velocity_remove1,
-#ifdef CONFIG_PM
- .suspend = velocity_suspend,
- .resume = velocity_resume,
-#endif
+ .id_table = velocity_pci_id_table,
+ .probe = velocity_pci_probe,
+ .remove = velocity_pci_remove,
+ .driver = {
+ .pm = &velocity_pm_ops,
+ },
};
+static struct platform_driver velocity_platform_driver = {
+ .probe = velocity_platform_probe,
+ .remove = velocity_platform_remove,
+ .driver = {
+ .name = "via-velocity",
+ .owner = THIS_MODULE,
+ .of_match_table = velocity_of_ids,
+ .pm = &velocity_pm_ops,
+ },
+};
/**
* velocity_ethtool_up - pre hook for ethtool
@@ -3134,7 +3275,7 @@ static int velocity_ethtool_up(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D0);
+ velocity_set_power_state(vptr, PCI_D0);
return 0;
}
@@ -3149,7 +3290,7 @@ static void velocity_ethtool_down(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D3hot);
+ velocity_set_power_state(vptr, PCI_D3hot);
}
static int velocity_get_settings(struct net_device *dev,
@@ -3269,9 +3410,14 @@ static int velocity_set_settings(struct net_device *dev,
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct velocity_info *vptr = netdev_priv(dev);
+
strlcpy(info->driver, VELOCITY_NAME, sizeof(info->driver));
strlcpy(info->version, VELOCITY_VERSION, sizeof(info->version));
- strlcpy(info->bus_info, pci_name(vptr->pdev), sizeof(info->bus_info));
+ if (vptr->pdev)
+ strlcpy(info->bus_info, pci_name(vptr->pdev),
+ sizeof(info->bus_info));
+ else
+ strlcpy(info->bus_info, "platform", sizeof(info->bus_info));
}
static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -3561,13 +3707,20 @@ static void velocity_unregister_notifier(void)
*/
static int __init velocity_init_module(void)
{
- int ret;
+ int ret_pci, ret_platform;
velocity_register_notifier();
- ret = pci_register_driver(&velocity_driver);
- if (ret < 0)
+
+ ret_pci = pci_register_driver(&velocity_pci_driver);
+ ret_platform = platform_driver_register(&velocity_platform_driver);
+
+ /* if both_registers failed, remove the notifier */
+ if ((ret_pci < 0) && (ret_platform < 0)) {
velocity_unregister_notifier();
- return ret;
+ return ret_pci;
+ }
+
+ return 0;
}
/**
@@ -3581,7 +3734,9 @@ static int __init velocity_init_module(void)
static void __exit velocity_cleanup_module(void)
{
velocity_unregister_notifier();
- pci_unregister_driver(&velocity_driver);
+
+ pci_unregister_driver(&velocity_pci_driver);
+ platform_driver_unregister(&velocity_platform_driver);
}
module_init(velocity_init_module);
diff --git a/drivers/net/ethernet/via/via-velocity.h b/drivers/net/ethernet/via/via-velocity.h
index 4cb9f13..9453bfa 100644
--- a/drivers/net/ethernet/via/via-velocity.h
+++ b/drivers/net/ethernet/via/via-velocity.h
@@ -1265,7 +1265,7 @@ struct velocity_context {
#define PHYID_VT3216_64BIT 0x000FC600UL
#define PHYID_MARVELL_1000 0x01410C50UL
#define PHYID_MARVELL_1000S 0x01410C40UL
-
+#define PHYID_ICPLUS_IP101A 0x02430C54UL
#define PHYID_REV_ID_MASK 0x0000000FUL
#define PHYID_GET_PHY_ID(i) ((i) & ~PHYID_REV_ID_MASK)
@@ -1434,8 +1434,10 @@ struct velocity_opt {
#define GET_RD_BY_IDX(vptr, idx) (vptr->rd_ring[idx])
struct velocity_info {
+ struct device *dev;
struct pci_dev *pdev;
- struct net_device *dev;
+ struct net_device *netdev;
+ int no_eeprom;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
u8 ip_addr[4];
@@ -1514,7 +1516,7 @@ static inline int velocity_get_ip(struct velocity_info *vptr)
int res = -ENOENT;
rcu_read_lock();
- in_dev = __in_dev_get_rcu(vptr->dev);
+ in_dev = __in_dev_get_rcu(vptr->netdev);
if (in_dev != NULL) {
ifa = (struct in_ifaddr *) in_dev->ifa_list;
if (ifa != NULL) {
diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c
index a518dca..30fed08 100644
--- a/drivers/net/ethernet/wiznet/w5100.c
+++ b/drivers/net/ethernet/wiznet/w5100.c
@@ -734,7 +734,6 @@ err_hw_probe:
unregister_netdev(ndev);
err_register:
free_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
return err;
}
@@ -750,7 +749,6 @@ static int w5100_remove(struct platform_device *pdev)
unregister_netdev(ndev);
free_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c
index 6e00e3f..e928845 100644
--- a/drivers/net/ethernet/wiznet/w5300.c
+++ b/drivers/net/ethernet/wiznet/w5300.c
@@ -646,7 +646,6 @@ err_hw_probe:
unregister_netdev(ndev);
err_register:
free_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
return err;
}
@@ -662,7 +661,6 @@ static int w5300_remove(struct platform_device *pdev)
unregister_netdev(ndev);
free_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig
index 122d60c..7b90a5e 100644
--- a/drivers/net/ethernet/xilinx/Kconfig
+++ b/drivers/net/ethernet/xilinx/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_XILINX
bool "Xilinx devices"
default y
- depends on PPC || PPC32 || MICROBLAZE
+ depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -20,7 +20,7 @@ if NET_VENDOR_XILINX
config XILINX_EMACLITE
tristate "Xilinx 10/100 Ethernet Lite support"
- depends on (PPC32 || MICROBLAZE)
+ depends on (PPC32 || MICROBLAZE || ARCH_ZYNQ)
select PHYLIB
---help---
This driver supports the 10/100 Ethernet Lite from Xilinx.
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index 57c2e5e..58eb448 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -1007,7 +1007,7 @@ static int temac_of_probe(struct platform_device *op)
return -ENOMEM;
ether_setup(ndev);
- dev_set_drvdata(&op->dev, ndev);
+ platform_set_drvdata(op, ndev);
SET_NETDEV_DEV(ndev, &op->dev);
ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
ndev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
@@ -1136,7 +1136,7 @@ static int temac_of_probe(struct platform_device *op)
static int temac_of_remove(struct platform_device *op)
{
- struct net_device *ndev = dev_get_drvdata(&op->dev);
+ struct net_device *ndev = platform_get_drvdata(op);
struct temac_local *lp = netdev_priv(ndev);
temac_mdio_teardown(lp);
@@ -1145,7 +1145,6 @@ static int temac_of_remove(struct platform_device *op)
if (lp->phy_node)
of_node_put(lp->phy_node);
lp->phy_node = NULL;
- dev_set_drvdata(&op->dev, NULL);
iounmap(lp->regs);
if (lp->sdma_regs)
iounmap(lp->sdma_regs);
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 24748e8..fb7d1c2 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -1484,7 +1484,7 @@ static int axienet_of_probe(struct platform_device *op)
return -ENOMEM;
ether_setup(ndev);
- dev_set_drvdata(&op->dev, ndev);
+ platform_set_drvdata(op, ndev);
SET_NETDEV_DEV(ndev, &op->dev);
ndev->flags &= ~IFF_MULTICAST; /* clear multicast */
@@ -1622,7 +1622,7 @@ nodev:
static int axienet_of_remove(struct platform_device *op)
{
- struct net_device *ndev = dev_get_drvdata(&op->dev);
+ struct net_device *ndev = platform_get_drvdata(op);
struct axienet_local *lp = netdev_priv(ndev);
axienet_mdio_teardown(lp);
@@ -1632,8 +1632,6 @@ static int axienet_of_remove(struct platform_device *op)
of_node_put(lp->phy_node);
lp->phy_node = NULL;
- dev_set_drvdata(&op->dev, NULL);
-
iounmap(lp->regs);
if (lp->dma_regs)
iounmap(lp->dma_regs);
diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
index 919b983..fd4dbda 100644
--- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c
+++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c
@@ -2,9 +2,9 @@
* Xilinx EmacLite Linux driver for the Xilinx Ethernet MAC Lite device.
*
* This is a new flat driver which is based on the original emac_lite
- * driver from John Williams <john.williams@petalogix.com>.
+ * driver from John Williams <john.williams@xilinx.com>.
*
- * 2007-2009 (c) Xilinx, Inc.
+ * 2007 - 2013 (c) Xilinx, Inc.
*
* 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
@@ -159,34 +159,32 @@ static void xemaclite_enable_interrupts(struct net_local *drvdata)
u32 reg_data;
/* Enable the Tx interrupts for the first Buffer */
- reg_data = in_be32(drvdata->base_addr + XEL_TSR_OFFSET);
- out_be32(drvdata->base_addr + XEL_TSR_OFFSET,
- reg_data | XEL_TSR_XMIT_IE_MASK);
+ reg_data = __raw_readl(drvdata->base_addr + XEL_TSR_OFFSET);
+ __raw_writel(reg_data | XEL_TSR_XMIT_IE_MASK,
+ drvdata->base_addr + XEL_TSR_OFFSET);
/* Enable the Tx interrupts for the second Buffer if
* configured in HW */
if (drvdata->tx_ping_pong != 0) {
- reg_data = in_be32(drvdata->base_addr +
+ reg_data = __raw_readl(drvdata->base_addr +
XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
- out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET +
- XEL_TSR_OFFSET,
- reg_data | XEL_TSR_XMIT_IE_MASK);
+ __raw_writel(reg_data | XEL_TSR_XMIT_IE_MASK,
+ drvdata->base_addr + XEL_BUFFER_OFFSET +
+ XEL_TSR_OFFSET);
}
/* Enable the Rx interrupts for the first buffer */
- out_be32(drvdata->base_addr + XEL_RSR_OFFSET,
- XEL_RSR_RECV_IE_MASK);
+ __raw_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr + XEL_RSR_OFFSET);
/* Enable the Rx interrupts for the second Buffer if
* configured in HW */
if (drvdata->rx_ping_pong != 0) {
- out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET +
- XEL_RSR_OFFSET,
- XEL_RSR_RECV_IE_MASK);
+ __raw_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr +
+ XEL_BUFFER_OFFSET + XEL_RSR_OFFSET);
}
/* Enable the Global Interrupt Enable */
- out_be32(drvdata->base_addr + XEL_GIER_OFFSET, XEL_GIER_GIE_MASK);
+ __raw_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET);
}
/**
@@ -201,37 +199,37 @@ static void xemaclite_disable_interrupts(struct net_local *drvdata)
u32 reg_data;
/* Disable the Global Interrupt Enable */
- out_be32(drvdata->base_addr + XEL_GIER_OFFSET, XEL_GIER_GIE_MASK);
+ __raw_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET);
/* Disable the Tx interrupts for the first buffer */
- reg_data = in_be32(drvdata->base_addr + XEL_TSR_OFFSET);
- out_be32(drvdata->base_addr + XEL_TSR_OFFSET,
- reg_data & (~XEL_TSR_XMIT_IE_MASK));
+ reg_data = __raw_readl(drvdata->base_addr + XEL_TSR_OFFSET);
+ __raw_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK),
+ drvdata->base_addr + XEL_TSR_OFFSET);
/* Disable the Tx interrupts for the second Buffer
* if configured in HW */
if (drvdata->tx_ping_pong != 0) {
- reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET +
+ reg_data = __raw_readl(drvdata->base_addr + XEL_BUFFER_OFFSET +
XEL_TSR_OFFSET);
- out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET +
- XEL_TSR_OFFSET,
- reg_data & (~XEL_TSR_XMIT_IE_MASK));
+ __raw_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK),
+ drvdata->base_addr + XEL_BUFFER_OFFSET +
+ XEL_TSR_OFFSET);
}
/* Disable the Rx interrupts for the first buffer */
- reg_data = in_be32(drvdata->base_addr + XEL_RSR_OFFSET);
- out_be32(drvdata->base_addr + XEL_RSR_OFFSET,
- reg_data & (~XEL_RSR_RECV_IE_MASK));
+ reg_data = __raw_readl(drvdata->base_addr + XEL_RSR_OFFSET);
+ __raw_writel(reg_data & (~XEL_RSR_RECV_IE_MASK),
+ drvdata->base_addr + XEL_RSR_OFFSET);
/* Disable the Rx interrupts for the second buffer
* if configured in HW */
if (drvdata->rx_ping_pong != 0) {
- reg_data = in_be32(drvdata->base_addr + XEL_BUFFER_OFFSET +
+ reg_data = __raw_readl(drvdata->base_addr + XEL_BUFFER_OFFSET +
XEL_RSR_OFFSET);
- out_be32(drvdata->base_addr + XEL_BUFFER_OFFSET +
- XEL_RSR_OFFSET,
- reg_data & (~XEL_RSR_RECV_IE_MASK));
+ __raw_writel(reg_data & (~XEL_RSR_RECV_IE_MASK),
+ drvdata->base_addr + XEL_BUFFER_OFFSET +
+ XEL_RSR_OFFSET);
}
}
@@ -351,7 +349,7 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data,
byte_count = ETH_FRAME_LEN;
/* Check if the expected buffer is available */
- reg_data = in_be32(addr + XEL_TSR_OFFSET);
+ reg_data = __raw_readl(addr + XEL_TSR_OFFSET);
if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK |
XEL_TSR_XMIT_ACTIVE_MASK)) == 0) {
@@ -364,7 +362,7 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data,
addr = (void __iomem __force *)((u32 __force)addr ^
XEL_BUFFER_OFFSET);
- reg_data = in_be32(addr + XEL_TSR_OFFSET);
+ reg_data = __raw_readl(addr + XEL_TSR_OFFSET);
if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK |
XEL_TSR_XMIT_ACTIVE_MASK)) != 0)
@@ -375,15 +373,16 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data,
/* Write the frame to the buffer */
xemaclite_aligned_write(data, (u32 __force *) addr, byte_count);
- out_be32(addr + XEL_TPLR_OFFSET, (byte_count & XEL_TPLR_LENGTH_MASK));
+ __raw_writel((byte_count & XEL_TPLR_LENGTH_MASK),
+ addr + XEL_TPLR_OFFSET);
/* Update the Tx Status Register to indicate that there is a
* frame to send. Set the XEL_TSR_XMIT_ACTIVE_MASK flag which
* is used by the interrupt handler to check whether a frame
* has been transmitted */
- reg_data = in_be32(addr + XEL_TSR_OFFSET);
+ reg_data = __raw_readl(addr + XEL_TSR_OFFSET);
reg_data |= (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK);
- out_be32(addr + XEL_TSR_OFFSET, reg_data);
+ __raw_writel(reg_data, addr + XEL_TSR_OFFSET);
return 0;
}
@@ -408,7 +407,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
addr = (drvdata->base_addr + drvdata->next_rx_buf_to_use);
/* Verify which buffer has valid data */
- reg_data = in_be32(addr + XEL_RSR_OFFSET);
+ reg_data = __raw_readl(addr + XEL_RSR_OFFSET);
if ((reg_data & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
if (drvdata->rx_ping_pong != 0)
@@ -425,14 +424,14 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
return 0; /* No data was available */
/* Verify that buffer has valid data */
- reg_data = in_be32(addr + XEL_RSR_OFFSET);
+ reg_data = __raw_readl(addr + XEL_RSR_OFFSET);
if ((reg_data & XEL_RSR_RECV_DONE_MASK) !=
XEL_RSR_RECV_DONE_MASK)
return 0; /* No data was available */
}
/* Get the protocol type of the ethernet frame that arrived */
- proto_type = ((ntohl(in_be32(addr + XEL_HEADER_OFFSET +
+ proto_type = ((ntohl(__raw_readl(addr + XEL_HEADER_OFFSET +
XEL_RXBUFF_OFFSET)) >> XEL_HEADER_SHIFT) &
XEL_RPLR_LENGTH_MASK);
@@ -441,7 +440,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
if (proto_type == ETH_P_IP) {
- length = ((ntohl(in_be32(addr +
+ length = ((ntohl(__raw_readl(addr +
XEL_HEADER_IP_LENGTH_OFFSET +
XEL_RXBUFF_OFFSET)) >>
XEL_HEADER_SHIFT) &
@@ -463,9 +462,9 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data)
data, length);
/* Acknowledge the frame */
- reg_data = in_be32(addr + XEL_RSR_OFFSET);
+ reg_data = __raw_readl(addr + XEL_RSR_OFFSET);
reg_data &= ~XEL_RSR_RECV_DONE_MASK;
- out_be32(addr + XEL_RSR_OFFSET, reg_data);
+ __raw_writel(reg_data, addr + XEL_RSR_OFFSET);
return length;
}
@@ -492,14 +491,14 @@ static void xemaclite_update_address(struct net_local *drvdata,
xemaclite_aligned_write(address_ptr, (u32 __force *) addr, ETH_ALEN);
- out_be32(addr + XEL_TPLR_OFFSET, ETH_ALEN);
+ __raw_writel(ETH_ALEN, addr + XEL_TPLR_OFFSET);
/* Update the MAC address in the EmacLite */
- reg_data = in_be32(addr + XEL_TSR_OFFSET);
- out_be32(addr + XEL_TSR_OFFSET, reg_data | XEL_TSR_PROG_MAC_ADDR);
+ reg_data = __raw_readl(addr + XEL_TSR_OFFSET);
+ __raw_writel(reg_data | XEL_TSR_PROG_MAC_ADDR, addr + XEL_TSR_OFFSET);
/* Wait for EmacLite to finish with the MAC address update */
- while ((in_be32(addr + XEL_TSR_OFFSET) &
+ while ((__raw_readl(addr + XEL_TSR_OFFSET) &
XEL_TSR_PROG_MAC_ADDR) != 0)
;
}
@@ -669,31 +668,32 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id)
u32 tx_status;
/* Check if there is Rx Data available */
- if ((in_be32(base_addr + XEL_RSR_OFFSET) & XEL_RSR_RECV_DONE_MASK) ||
- (in_be32(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET)
+ if ((__raw_readl(base_addr + XEL_RSR_OFFSET) &
+ XEL_RSR_RECV_DONE_MASK) ||
+ (__raw_readl(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET)
& XEL_RSR_RECV_DONE_MASK))
xemaclite_rx_handler(dev);
/* Check if the Transmission for the first buffer is completed */
- tx_status = in_be32(base_addr + XEL_TSR_OFFSET);
+ tx_status = __raw_readl(base_addr + XEL_TSR_OFFSET);
if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) &&
(tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) {
tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK;
- out_be32(base_addr + XEL_TSR_OFFSET, tx_status);
+ __raw_writel(tx_status, base_addr + XEL_TSR_OFFSET);
tx_complete = true;
}
/* Check if the Transmission for the second buffer is completed */
- tx_status = in_be32(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
+ tx_status = __raw_readl(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) &&
(tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) {
tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK;
- out_be32(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET,
- tx_status);
+ __raw_writel(tx_status, base_addr + XEL_BUFFER_OFFSET +
+ XEL_TSR_OFFSET);
tx_complete = true;
}
@@ -726,7 +726,7 @@ static int xemaclite_mdio_wait(struct net_local *lp)
/* wait for the MDIO interface to not be busy or timeout
after some time.
*/
- while (in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
+ while (__raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET) &
XEL_MDIOCTRL_MDIOSTS_MASK) {
if (end - jiffies <= 0) {
WARN_ON(1);
@@ -762,17 +762,17 @@ static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg)
* MDIO Address register. Set the Status bit in the MDIO Control
* register to start a MDIO read transaction.
*/
- ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
- out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
- XEL_MDIOADDR_OP_MASK |
- ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
- out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
- ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+ ctrl_reg = __raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+ __raw_writel(XEL_MDIOADDR_OP_MASK |
+ ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg),
+ lp->base_addr + XEL_MDIOADDR_OFFSET);
+ __raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK,
+ lp->base_addr + XEL_MDIOCTRL_OFFSET);
if (xemaclite_mdio_wait(lp))
return -ETIMEDOUT;
- rc = in_be32(lp->base_addr + XEL_MDIORD_OFFSET);
+ rc = __raw_readl(lp->base_addr + XEL_MDIORD_OFFSET);
dev_dbg(&lp->ndev->dev,
"xemaclite_mdio_read(phy_id=%i, reg=%x) == %x\n",
@@ -809,13 +809,13 @@ static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg,
* Data register. Finally, set the Status bit in the MDIO Control
* register to start a MDIO write transaction.
*/
- ctrl_reg = in_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET);
- out_be32(lp->base_addr + XEL_MDIOADDR_OFFSET,
- ~XEL_MDIOADDR_OP_MASK &
- ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg));
- out_be32(lp->base_addr + XEL_MDIOWR_OFFSET, val);
- out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
- ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+ ctrl_reg = __raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET);
+ __raw_writel(~XEL_MDIOADDR_OP_MASK &
+ ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg),
+ lp->base_addr + XEL_MDIOADDR_OFFSET);
+ __raw_writel(val, lp->base_addr + XEL_MDIOWR_OFFSET);
+ __raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK,
+ lp->base_addr + XEL_MDIOCTRL_OFFSET);
return 0;
}
@@ -848,24 +848,39 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
int rc;
struct resource res;
struct device_node *np = of_get_parent(lp->phy_node);
+ struct device_node *npp;
/* Don't register the MDIO bus if the phy_node or its parent node
* can't be found.
*/
- if (!np)
+ if (!np) {
+ dev_err(dev, "Failed to register mdio bus.\n");
return -ENODEV;
+ }
+ npp = of_get_parent(np);
+
+ of_address_to_resource(npp, 0, &res);
+ if (lp->ndev->mem_start != res.start) {
+ struct phy_device *phydev;
+ phydev = of_phy_find_device(lp->phy_node);
+ if (!phydev)
+ dev_info(dev,
+ "MDIO of the phy is not registered yet\n");
+ return 0;
+ }
/* Enable the MDIO bus by asserting the enable bit in MDIO Control
* register.
*/
- out_be32(lp->base_addr + XEL_MDIOCTRL_OFFSET,
- XEL_MDIOCTRL_MDIOEN_MASK);
+ __raw_writel(XEL_MDIOCTRL_MDIOEN_MASK,
+ lp->base_addr + XEL_MDIOCTRL_OFFSET);
bus = mdiobus_alloc();
- if (!bus)
+ if (!bus) {
+ dev_err(dev, "Failed to allocate mdiobus\n");
return -ENOMEM;
+ }
- of_address_to_resource(np, 0, &res);
snprintf(bus->id, MII_BUS_ID_SIZE, "%.8llx",
(unsigned long long)res.start);
bus->priv = lp;
@@ -879,8 +894,10 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
lp->mii_bus = bus;
rc = of_mdiobus_register(bus, np);
- if (rc)
+ if (rc) {
+ dev_err(dev, "Failed to register mdio bus.\n");
goto err_register;
+ }
return 0;
@@ -896,7 +913,7 @@ err_register:
* There's nothing in the Emaclite device to be configured when the link
* state changes. We just print the status.
*/
-void xemaclite_adjust_link(struct net_device *ndev)
+static void xemaclite_adjust_link(struct net_device *ndev)
{
struct net_local *lp = netdev_priv(ndev);
struct phy_device *phy = lp->phy_dev;
@@ -946,7 +963,8 @@ static int xemaclite_open(struct net_device *dev)
phy_write(lp->phy_dev, MII_CTRL1000, 0);
/* Advertise only 10 and 100mbps full/half duplex speeds */
- phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL);
+ phy_write(lp->phy_dev, MII_ADVERTISE, ADVERTISE_ALL |
+ ADVERTISE_CSMA);
/* Restart auto negotiation */
bmcr = phy_read(lp->phy_dev, MII_BMCR);
@@ -1057,13 +1075,14 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
* This function un maps the IO region of the Emaclite device and frees the net
* device.
*/
-static void xemaclite_remove_ndev(struct net_device *ndev)
+static void xemaclite_remove_ndev(struct net_device *ndev,
+ struct platform_device *pdev)
{
if (ndev) {
struct net_local *lp = netdev_priv(ndev);
if (lp->base_addr)
- iounmap((void __iomem __force *) (lp->base_addr));
+ devm_iounmap(&pdev->dev, lp->base_addr);
free_netdev(ndev);
}
}
@@ -1109,8 +1128,7 @@ static struct net_device_ops xemaclite_netdev_ops;
*/
static int xemaclite_of_probe(struct platform_device *ofdev)
{
- struct resource r_irq; /* Interrupt resources */
- struct resource r_mem; /* IO mem resources */
+ struct resource *res;
struct net_device *ndev = NULL;
struct net_local *lp = NULL;
struct device *dev = &ofdev->dev;
@@ -1120,20 +1138,6 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
dev_info(dev, "Device Tree Probing\n");
- /* Get iospace for the device */
- rc = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
- if (rc) {
- dev_err(dev, "invalid address\n");
- return rc;
- }
-
- /* Get IRQ for the device */
- rc = of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq);
- if (!rc) {
- dev_err(dev, "no IRQ found\n");
- return rc;
- }
-
/* Create an ethernet device instance */
ndev = alloc_etherdev(sizeof(struct net_local));
if (!ndev)
@@ -1142,30 +1146,28 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
dev_set_drvdata(dev, ndev);
SET_NETDEV_DEV(ndev, &ofdev->dev);
- ndev->irq = r_irq.start;
- ndev->mem_start = r_mem.start;
- ndev->mem_end = r_mem.end;
-
lp = netdev_priv(ndev);
lp->ndev = ndev;
- if (!request_mem_region(ndev->mem_start,
- ndev->mem_end - ndev->mem_start + 1,
- DRIVER_NAME)) {
- dev_err(dev, "Couldn't lock memory region at %p\n",
- (void *)ndev->mem_start);
- rc = -EBUSY;
- goto error2;
+ /* Get IRQ for the device */
+ res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(dev, "no IRQ found\n");
+ goto error;
}
- /* Get the virtual base address for the device */
- lp->base_addr = ioremap(r_mem.start, resource_size(&r_mem));
- if (NULL == lp->base_addr) {
- dev_err(dev, "EmacLite: Could not allocate iomem\n");
- rc = -EIO;
- goto error1;
+ ndev->irq = res->start;
+
+ res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+ lp->base_addr = devm_ioremap_resource(&ofdev->dev, res);
+ if (IS_ERR(lp->base_addr)) {
+ rc = PTR_ERR(lp->base_addr);
+ goto error;
}
+ ndev->mem_start = res->start;
+ ndev->mem_end = res->end;
+
spin_lock_init(&lp->reset_lock);
lp->next_tx_buf_to_use = 0x0;
lp->next_rx_buf_to_use = 0x0;
@@ -1180,8 +1182,8 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
dev_warn(dev, "No MAC address found\n");
/* Clear the Tx CSR's in case this is a restart */
- out_be32(lp->base_addr + XEL_TSR_OFFSET, 0);
- out_be32(lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET, 0);
+ __raw_writel(0, lp->base_addr + XEL_TSR_OFFSET);
+ __raw_writel(0, lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET);
/* Set the MAC address in the EmacLite device */
xemaclite_update_address(lp, ndev->dev_addr);
@@ -1202,7 +1204,7 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
if (rc) {
dev_err(dev,
"Cannot register network device, aborting\n");
- goto error1;
+ goto error;
}
dev_info(dev,
@@ -1211,11 +1213,8 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
(unsigned int __force)lp->base_addr, ndev->irq);
return 0;
-error1:
- release_mem_region(ndev->mem_start, resource_size(&r_mem));
-
-error2:
- xemaclite_remove_ndev(ndev);
+error:
+ xemaclite_remove_ndev(ndev, ofdev);
return rc;
}
@@ -1250,9 +1249,7 @@ static int xemaclite_of_remove(struct platform_device *of_dev)
of_node_put(lp->phy_node);
lp->phy_node = NULL;
- release_mem_region(ndev->mem_start, ndev->mem_end-ndev->mem_start + 1);
-
- xemaclite_remove_ndev(ndev);
+ xemaclite_remove_ndev(ndev, of_dev);
dev_set_drvdata(dev, NULL);
return 0;
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index 6958a5e..3d689fc 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -1472,7 +1472,6 @@ err_phy_dis:
phy_disconnect(port->phydev);
err_free_mem:
npe_port_tab[NPE_ID(port->id)] = NULL;
- platform_set_drvdata(pdev, NULL);
release_resource(port->mem_res);
err_npe_rel:
npe_release(port->npe);
@@ -1489,7 +1488,6 @@ static int eth_remove_one(struct platform_device *pdev)
unregister_netdev(dev);
phy_disconnect(port->phydev);
npe_port_tab[NPE_ID(port->id)] = NULL;
- platform_set_drvdata(pdev, NULL);
npe_release(port->npe);
release_resource(port->mem_res);
free_netdev(dev);
diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c
index d5bd563..f5d7305 100644
--- a/drivers/net/fddi/skfp/skfddi.c
+++ b/drivers/net/fddi/skfp/skfddi.c
@@ -2246,15 +2246,4 @@ static struct pci_driver skfddi_pci_driver = {
.remove = skfp_remove_one,
};
-static int __init skfd_init(void)
-{
- return pci_register_driver(&skfddi_pci_driver);
-}
-
-static void __exit skfd_exit(void)
-{
- pci_unregister_driver(&skfddi_pci_driver);
-}
-
-module_init(skfd_init);
-module_exit(skfd_exit);
+module_pci_driver(skfddi_pci_driver);
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 02de6c8..f91bf0d 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -103,7 +103,7 @@ static struct packet_type bpq_packet_type __read_mostly = {
};
static struct notifier_block bpq_dev_notifier = {
- .notifier_call =bpq_device_event,
+ .notifier_call = bpq_device_event,
};
@@ -544,9 +544,10 @@ static void bpq_free_device(struct net_device *ndev)
/*
* Handle device status changes.
*/
-static int bpq_device_event(struct notifier_block *this,unsigned long event, void *ptr)
+static int bpq_device_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
{
- struct net_device *dev = (struct net_device *)ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (!net_eq(dev_net(dev), &init_net))
return NOTIFY_DONE;
diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c
index 3c4d627..00ed751 100644
--- a/drivers/net/hippi/rrunner.c
+++ b/drivers/net/hippi/rrunner.c
@@ -1686,15 +1686,4 @@ static struct pci_driver rr_driver = {
.remove = rr_remove_one,
};
-static int __init rr_init_module(void)
-{
- return pci_register_driver(&rr_driver);
-}
-
-static void __exit rr_cleanup_module(void)
-{
- pci_unregister_driver(&rr_driver);
-}
-
-module_init(rr_init_module);
-module_exit(rr_cleanup_module);
+module_pci_driver(rr_driver);
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 088c554..4dccead 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -31,6 +31,7 @@
#include <linux/inetdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/slab.h>
#include <net/arp.h>
@@ -284,7 +285,9 @@ int netvsc_recv_callback(struct hv_device *device_obj,
skb->protocol = eth_type_trans(skb, net);
skb->ip_summed = CHECKSUM_NONE;
- skb->vlan_tci = packet->vlan_tci;
+ if (packet->vlan_tci & VLAN_TAG_PRESENT)
+ __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
+ packet->vlan_tci);
net->stats.rx_packets++;
net->stats.rx_bytes += packet->total_data_buflen;
diff --git a/drivers/net/irda/bfin_sir.c b/drivers/net/irda/bfin_sir.c
index 22b4527..c74f384 100644
--- a/drivers/net/irda/bfin_sir.c
+++ b/drivers/net/irda/bfin_sir.c
@@ -794,7 +794,6 @@ static int bfin_sir_remove(struct platform_device *pdev)
kfree(self->rx_buff.head);
free_netdev(dev);
kfree(sir_port);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c
index 9448587..4455425 100644
--- a/drivers/net/irda/sh_irda.c
+++ b/drivers/net/irda/sh_irda.c
@@ -838,7 +838,6 @@ static int sh_irda_remove(struct platform_device *pdev)
sh_irda_remove_iobuf(self);
iounmap(self->membase);
free_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index 24aefcd..89682b4 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -796,7 +796,6 @@ static int sh_sir_remove(struct platform_device *pdev)
sh_sir_remove_iobuf(self);
iounmap(self->membase);
free_netdev(ndev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index d5a141c..d811b06 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -229,7 +229,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
}
if (port->passthru)
- vlan = list_first_entry(&port->vlans, struct macvlan_dev, list);
+ vlan = list_first_or_null_rcu(&port->vlans,
+ struct macvlan_dev, list);
else
vlan = macvlan_hash_lookup(port, eth->h_dest);
if (vlan == NULL)
@@ -814,7 +815,7 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
if (err < 0)
goto upper_dev_unlink;
- list_add_tail(&vlan->list, &port->vlans);
+ list_add_tail_rcu(&vlan->list, &port->vlans);
netif_stacked_transfer_operstate(lowerdev, dev);
return 0;
@@ -842,7 +843,7 @@ void macvlan_dellink(struct net_device *dev, struct list_head *head)
{
struct macvlan_dev *vlan = netdev_priv(dev);
- list_del(&vlan->list);
+ list_del_rcu(&vlan->list);
unregister_netdevice_queue(dev, head);
netdev_upper_dev_unlink(vlan->lowerdev, dev);
}
@@ -852,18 +853,24 @@ static int macvlan_changelink(struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct macvlan_dev *vlan = netdev_priv(dev);
- if (data && data[IFLA_MACVLAN_MODE])
- vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+
if (data && data[IFLA_MACVLAN_FLAGS]) {
__u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC;
-
- if (promisc && (flags & MACVLAN_FLAG_NOPROMISC))
- dev_set_promiscuity(vlan->lowerdev, -1);
- else if (promisc && !(flags & MACVLAN_FLAG_NOPROMISC))
- dev_set_promiscuity(vlan->lowerdev, 1);
+ if (vlan->port->passthru && promisc) {
+ int err;
+
+ if (flags & MACVLAN_FLAG_NOPROMISC)
+ err = dev_set_promiscuity(vlan->lowerdev, -1);
+ else
+ err = dev_set_promiscuity(vlan->lowerdev, 1);
+ if (err < 0)
+ return err;
+ }
vlan->flags = flags;
}
+ if (data && data[IFLA_MACVLAN_MODE])
+ vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
return 0;
}
@@ -920,7 +927,7 @@ static struct rtnl_link_ops macvlan_link_ops = {
static int macvlan_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct macvlan_dev *vlan, *next;
struct macvlan_port *port;
LIST_HEAD(list_kill);
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 59e9605..5a76f20 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -31,10 +31,6 @@
* macvtap_proto is used to allocate queues through the sock allocation
* mechanism.
*
- * TODO: multiqueue support is currently not implemented, even though
- * macvtap is basically prepared for that. We will need to add this
- * here as well as in virtio-net and qemu to get line rate on 10gbit
- * adapters from a guest.
*/
struct macvtap_queue {
struct sock sk;
@@ -44,6 +40,9 @@ struct macvtap_queue {
struct macvlan_dev __rcu *vlan;
struct file *file;
unsigned int flags;
+ u16 queue_index;
+ bool enabled;
+ struct list_head next;
};
static struct proto macvtap_proto = {
@@ -84,52 +83,96 @@ static const struct proto_ops macvtap_socket_ops;
*/
static DEFINE_SPINLOCK(macvtap_lock);
-/*
- * get_slot: return a [unused/occupied] slot in vlan->taps[]:
- * - if 'q' is NULL, return the first empty slot;
- * - otherwise, return the slot this pointer occupies.
- */
-static int get_slot(struct macvlan_dev *vlan, struct macvtap_queue *q)
+static int macvtap_enable_queue(struct net_device *dev, struct file *file,
+ struct macvtap_queue *q)
{
- int i;
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ int err = -EINVAL;
- for (i = 0; i < MAX_MACVTAP_QUEUES; i++) {
- if (rcu_dereference_protected(vlan->taps[i],
- lockdep_is_held(&macvtap_lock)) == q)
- return i;
- }
+ spin_lock(&macvtap_lock);
- /* Should never happen */
- BUG_ON(1);
+ if (q->enabled)
+ goto out;
+
+ err = 0;
+ rcu_assign_pointer(vlan->taps[vlan->numvtaps], q);
+ q->queue_index = vlan->numvtaps;
+ q->enabled = true;
+
+ vlan->numvtaps++;
+out:
+ spin_unlock(&macvtap_lock);
+ return err;
}
static int macvtap_set_queue(struct net_device *dev, struct file *file,
- struct macvtap_queue *q)
+ struct macvtap_queue *q)
{
struct macvlan_dev *vlan = netdev_priv(dev);
- int index;
int err = -EBUSY;
spin_lock(&macvtap_lock);
- if (vlan->numvtaps == MAX_MACVTAP_QUEUES)
+ if (vlan->numqueues == MAX_MACVTAP_QUEUES)
goto out;
err = 0;
- index = get_slot(vlan, NULL);
rcu_assign_pointer(q->vlan, vlan);
- rcu_assign_pointer(vlan->taps[index], q);
+ rcu_assign_pointer(vlan->taps[vlan->numvtaps], q);
sock_hold(&q->sk);
q->file = file;
+ q->queue_index = vlan->numvtaps;
+ q->enabled = true;
file->private_data = q;
+ list_add_tail(&q->next, &vlan->queue_list);
vlan->numvtaps++;
+ vlan->numqueues++;
out:
spin_unlock(&macvtap_lock);
return err;
}
+static int __macvtap_disable_queue(struct macvtap_queue *q)
+{
+ struct macvlan_dev *vlan;
+ struct macvtap_queue *nq;
+
+ vlan = rcu_dereference_protected(q->vlan,
+ lockdep_is_held(&macvtap_lock));
+
+ if (!q->enabled)
+ return -EINVAL;
+
+ if (vlan) {
+ int index = q->queue_index;
+ BUG_ON(index >= vlan->numvtaps);
+ nq = rcu_dereference_protected(vlan->taps[vlan->numvtaps - 1],
+ lockdep_is_held(&macvtap_lock));
+ nq->queue_index = index;
+
+ rcu_assign_pointer(vlan->taps[index], nq);
+ RCU_INIT_POINTER(vlan->taps[vlan->numvtaps - 1], NULL);
+ q->enabled = false;
+
+ vlan->numvtaps--;
+ }
+
+ return 0;
+}
+
+static int macvtap_disable_queue(struct macvtap_queue *q)
+{
+ int err;
+
+ spin_lock(&macvtap_lock);
+ err = __macvtap_disable_queue(q);
+ spin_unlock(&macvtap_lock);
+
+ return err;
+}
+
/*
* The file owning the queue got closed, give up both
* the reference that the files holds as well as the
@@ -146,12 +189,13 @@ static void macvtap_put_queue(struct macvtap_queue *q)
vlan = rcu_dereference_protected(q->vlan,
lockdep_is_held(&macvtap_lock));
if (vlan) {
- int index = get_slot(vlan, q);
+ if (q->enabled)
+ BUG_ON(__macvtap_disable_queue(q));
- RCU_INIT_POINTER(vlan->taps[index], NULL);
+ vlan->numqueues--;
RCU_INIT_POINTER(q->vlan, NULL);
sock_put(&q->sk);
- --vlan->numvtaps;
+ list_del_init(&q->next);
}
spin_unlock(&macvtap_lock);
@@ -172,7 +216,12 @@ static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct macvtap_queue *tap = NULL;
- int numvtaps = vlan->numvtaps;
+ /* Access to taps array is protected by rcu, but access to numvtaps
+ * isn't. Below we use it to lookup a queue, but treat it as a hint
+ * and validate that the result isn't NULL - in case we are
+ * racing against queue removal.
+ */
+ int numvtaps = ACCESS_ONCE(vlan->numvtaps);
__u32 rxq;
if (!numvtaps)
@@ -182,8 +231,7 @@ static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
rxq = skb_get_rxhash(skb);
if (rxq) {
tap = rcu_dereference(vlan->taps[rxq % numvtaps]);
- if (tap)
- goto out;
+ goto out;
}
if (likely(skb_rx_queue_recorded(skb))) {
@@ -193,17 +241,10 @@ static struct macvtap_queue *macvtap_get_queue(struct net_device *dev,
rxq -= numvtaps;
tap = rcu_dereference(vlan->taps[rxq]);
- if (tap)
- goto out;
- }
-
- /* Everything failed - find first available queue */
- for (rxq = 0; rxq < MAX_MACVTAP_QUEUES; rxq++) {
- tap = rcu_dereference(vlan->taps[rxq]);
- if (tap)
- break;
+ goto out;
}
+ tap = rcu_dereference(vlan->taps[0]);
out:
return tap;
}
@@ -216,22 +257,22 @@ out:
static void macvtap_del_queues(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
- struct macvtap_queue *q, *qlist[MAX_MACVTAP_QUEUES];
+ struct macvtap_queue *q, *tmp, *qlist[MAX_MACVTAP_QUEUES];
int i, j = 0;
- /* macvtap_put_queue can free some slots, so go through all slots */
spin_lock(&macvtap_lock);
- for (i = 0; i < MAX_MACVTAP_QUEUES && vlan->numvtaps; i++) {
- q = rcu_dereference_protected(vlan->taps[i],
- lockdep_is_held(&macvtap_lock));
- if (q) {
- qlist[j++] = q;
- RCU_INIT_POINTER(vlan->taps[i], NULL);
- RCU_INIT_POINTER(q->vlan, NULL);
+ list_for_each_entry_safe(q, tmp, &vlan->queue_list, next) {
+ list_del_init(&q->next);
+ qlist[j++] = q;
+ RCU_INIT_POINTER(q->vlan, NULL);
+ if (q->enabled)
vlan->numvtaps--;
- }
+ vlan->numqueues--;
}
- BUG_ON(vlan->numvtaps != 0);
+ for (i = 0; i < vlan->numvtaps; i++)
+ RCU_INIT_POINTER(vlan->taps[i], NULL);
+ BUG_ON(vlan->numvtaps);
+ BUG_ON(vlan->numqueues);
/* guarantee that any future macvtap_set_queue will fail */
vlan->numvtaps = MAX_MACVTAP_QUEUES;
spin_unlock(&macvtap_lock);
@@ -322,6 +363,9 @@ static int macvtap_newlink(struct net *src_net,
struct nlattr *tb[],
struct nlattr *data[])
{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ INIT_LIST_HEAD(&vlan->queue_list);
+
/* Don't put anything that may fail after macvlan_common_newlink
* because we can't undo what it does.
*/
@@ -385,7 +429,7 @@ static int macvtap_open(struct inode *inode, struct file *file)
if (!q)
goto out;
- q->sock.wq = &q->wq;
+ RCU_INIT_POINTER(q->sock.wq, &q->wq);
init_waitqueue_head(&q->wq.wait);
q->sock.type = SOCK_RAW;
q->sock.state = SS_CONNECTED;
@@ -845,7 +889,9 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
ssize_t ret = 0;
while (len) {
- prepare_to_wait(sk_sleep(&q->sk), &wait, TASK_INTERRUPTIBLE);
+ if (!noblock)
+ prepare_to_wait(sk_sleep(&q->sk), &wait,
+ TASK_INTERRUPTIBLE);
/* Read frames from the queue */
skb = skb_dequeue(&q->sk.sk_receive_queue);
@@ -867,7 +913,8 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
break;
}
- finish_wait(sk_sleep(&q->sk), &wait);
+ if (!noblock)
+ finish_wait(sk_sleep(&q->sk), &wait);
return ret;
}
@@ -890,6 +937,45 @@ out:
return ret;
}
+static struct macvlan_dev *macvtap_get_vlan(struct macvtap_queue *q)
+{
+ struct macvlan_dev *vlan;
+
+ rcu_read_lock_bh();
+ vlan = rcu_dereference_bh(q->vlan);
+ if (vlan)
+ dev_hold(vlan->dev);
+ rcu_read_unlock_bh();
+
+ return vlan;
+}
+
+static void macvtap_put_vlan(struct macvlan_dev *vlan)
+{
+ dev_put(vlan->dev);
+}
+
+static int macvtap_ioctl_set_queue(struct file *file, unsigned int flags)
+{
+ struct macvtap_queue *q = file->private_data;
+ struct macvlan_dev *vlan;
+ int ret;
+
+ vlan = macvtap_get_vlan(q);
+ if (!vlan)
+ return -EINVAL;
+
+ if (flags & IFF_ATTACH_QUEUE)
+ ret = macvtap_enable_queue(vlan->dev, file, q);
+ else if (flags & IFF_DETACH_QUEUE)
+ ret = macvtap_disable_queue(q);
+ else
+ ret = -EINVAL;
+
+ macvtap_put_vlan(vlan);
+ return ret;
+}
+
/*
* provide compatibility with generic tun/tap interface
*/
@@ -913,7 +999,8 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
ret = 0;
- if ((u & ~IFF_VNET_HDR) != (IFF_NO_PI | IFF_TAP))
+ if ((u & ~(IFF_VNET_HDR | IFF_MULTI_QUEUE)) !=
+ (IFF_NO_PI | IFF_TAP))
ret = -EINVAL;
else
q->flags = u;
@@ -921,12 +1008,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
return ret;
case TUNGETIFF:
- rcu_read_lock_bh();
- vlan = rcu_dereference_bh(q->vlan);
- if (vlan)
- dev_hold(vlan->dev);
- rcu_read_unlock_bh();
-
+ vlan = macvtap_get_vlan(q);
if (!vlan)
return -ENOLINK;
@@ -934,11 +1016,17 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) ||
put_user(q->flags, &ifr->ifr_flags))
ret = -EFAULT;
- dev_put(vlan->dev);
+ macvtap_put_vlan(vlan);
return ret;
+ case TUNSETQUEUE:
+ if (get_user(u, &ifr->ifr_flags))
+ return -EFAULT;
+ return macvtap_ioctl_set_queue(file, u);
+
case TUNGETFEATURES:
- if (put_user(IFF_TAP | IFF_NO_PI | IFF_VNET_HDR, up))
+ if (put_user(IFF_TAP | IFF_NO_PI | IFF_VNET_HDR |
+ IFF_MULTI_QUEUE, up))
return -EFAULT;
return 0;
@@ -1053,7 +1141,7 @@ EXPORT_SYMBOL_GPL(macvtap_get_socket);
static int macvtap_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct macvlan_dev *vlan;
struct device *classdev;
dev_t devt;
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 59ac143..1d1d0a1 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -653,12 +653,11 @@ static struct configfs_subsystem netconsole_subsys = {
/* Handle network interface device notifications */
static int netconsole_netdev_event(struct notifier_block *this,
- unsigned long event,
- void *ptr)
+ unsigned long event, void *ptr)
{
unsigned long flags;
struct netconsole_target *nt;
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
bool stopped = false;
if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c
index ed947dd..f3cdf64 100644
--- a/drivers/net/ntb_netdev.c
+++ b/drivers/net/ntb_netdev.c
@@ -375,6 +375,8 @@ static void ntb_netdev_remove(struct pci_dev *pdev)
if (dev == NULL)
return;
+ list_del(&dev->list);
+
ndev = dev->ndev;
unregister_netdev(ndev);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 1e11f2b..3a316b3 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -144,6 +144,16 @@ config MDIO_OCTEON
If in doubt, say Y.
+config MDIO_SUN4I
+ tristate "Allwinner sun4i MDIO interface support"
+ depends on ARCH_SUNXI
+ select REGULATOR
+ select REGULATOR_FIXED_VOLTAGE
+ help
+ This driver supports the MDIO interface found in the network
+ interface units of the Allwinner SoC that have an EMAC (A10,
+ A12, A10s, etc.)
+
config MDIO_BUS_MUX
tristate
depends on OF_MDIO
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 9645e38..23a2ab2 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_AMD_PHY) += amd.o
obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o
obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o
obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
+obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index 45cbc10..1f7091b 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -27,15 +27,22 @@
#define AT803X_MMD_ACCESS_CONTROL 0x0D
#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
#define AT803X_FUNC_DATA 0x4003
+#define AT803X_DEBUG_ADDR 0x1D
+#define AT803X_DEBUG_DATA 0x1E
+#define AT803X_DEBUG_SYSTEM_MODE_CTRL 0x05
+#define AT803X_DEBUG_RGMII_TX_CLK_DLY BIT(8)
MODULE_DESCRIPTION("Atheros 803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");
-static void at803x_set_wol_mac_addr(struct phy_device *phydev)
+static int at803x_set_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
{
struct net_device *ndev = phydev->attached_dev;
const u8 *mac;
+ int ret;
+ u32 value;
unsigned int i, offsets[] = {
AT803X_LOC_MAC_ADDR_32_47_OFFSET,
AT803X_LOC_MAC_ADDR_16_31_OFFSET,
@@ -43,30 +50,61 @@ static void at803x_set_wol_mac_addr(struct phy_device *phydev)
};
if (!ndev)
- return;
+ return -ENODEV;
- mac = (const u8 *) ndev->dev_addr;
+ if (wol->wolopts & WAKE_MAGIC) {
+ mac = (const u8 *) ndev->dev_addr;
- if (!is_valid_ether_addr(mac))
- return;
+ if (!is_valid_ether_addr(mac))
+ return -EFAULT;
- for (i = 0; i < 3; i++) {
- phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
+ for (i = 0; i < 3; i++) {
+ phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
AT803X_DEVICE_ADDR);
- phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
+ phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
offsets[i]);
- phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
+ phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
AT803X_FUNC_DATA);
- phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
+ phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
+ }
+
+ value = phy_read(phydev, AT803X_INTR_ENABLE);
+ value |= AT803X_WOL_ENABLE;
+ ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
+ if (ret)
+ return ret;
+ value = phy_read(phydev, AT803X_INTR_STATUS);
+ } else {
+ value = phy_read(phydev, AT803X_INTR_ENABLE);
+ value &= (~AT803X_WOL_ENABLE);
+ ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
+ if (ret)
+ return ret;
+ value = phy_read(phydev, AT803X_INTR_STATUS);
}
+
+ return ret;
+}
+
+static void at803x_get_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ u32 value;
+
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = 0;
+
+ value = phy_read(phydev, AT803X_INTR_ENABLE);
+ if (value & AT803X_WOL_ENABLE)
+ wol->wolopts |= WAKE_MAGIC;
}
static int at803x_config_init(struct phy_device *phydev)
{
int val;
+ int ret;
u32 features;
- int status;
features = SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI |
SUPPORTED_FIBRE | SUPPORTED_BNC;
@@ -100,20 +138,29 @@ static int at803x_config_init(struct phy_device *phydev)
phydev->supported = features;
phydev->advertising = features;
- /* enable WOL */
- at803x_set_wol_mac_addr(phydev);
- status = phy_write(phydev, AT803X_INTR_ENABLE, AT803X_WOL_ENABLE);
- status = phy_read(phydev, AT803X_INTR_STATUS);
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+ ret = phy_write(phydev, AT803X_DEBUG_ADDR,
+ AT803X_DEBUG_SYSTEM_MODE_CTRL);
+ if (ret)
+ return ret;
+ ret = phy_write(phydev, AT803X_DEBUG_DATA,
+ AT803X_DEBUG_RGMII_TX_CLK_DLY);
+ if (ret)
+ return ret;
+ }
return 0;
}
-/* ATHEROS 8035 */
-static struct phy_driver at8035_driver = {
+static struct phy_driver at803x_driver[] = {
+{
+ /* ATHEROS 8035 */
.phy_id = 0x004dd072,
.name = "Atheros 8035 ethernet",
.phy_id_mask = 0xffffffef,
.config_init = at803x_config_init,
+ .set_wol = at803x_set_wol,
+ .get_wol = at803x_get_wol,
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = &genphy_config_aneg,
@@ -121,14 +168,14 @@ static struct phy_driver at8035_driver = {
.driver = {
.owner = THIS_MODULE,
},
-};
-
-/* ATHEROS 8030 */
-static struct phy_driver at8030_driver = {
+}, {
+ /* ATHEROS 8030 */
.phy_id = 0x004dd076,
.name = "Atheros 8030 ethernet",
.phy_id_mask = 0xffffffef,
.config_init = at803x_config_init,
+ .set_wol = at803x_set_wol,
+ .get_wol = at803x_get_wol,
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = &genphy_config_aneg,
@@ -136,32 +183,33 @@ static struct phy_driver at8030_driver = {
.driver = {
.owner = THIS_MODULE,
},
-};
+}, {
+ /* ATHEROS 8031 */
+ .phy_id = 0x004dd074,
+ .name = "Atheros 8031 ethernet",
+ .phy_id_mask = 0xffffffef,
+ .config_init = at803x_config_init,
+ .set_wol = at803x_set_wol,
+ .get_wol = at803x_get_wol,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+} };
static int __init atheros_init(void)
{
- int ret;
-
- ret = phy_driver_register(&at8035_driver);
- if (ret)
- goto err1;
-
- ret = phy_driver_register(&at8030_driver);
- if (ret)
- goto err2;
-
- return 0;
-
-err2:
- phy_driver_unregister(&at8035_driver);
-err1:
- return ret;
+ return phy_drivers_register(at803x_driver,
+ ARRAY_SIZE(at803x_driver));
}
static void __exit atheros_exit(void)
{
- phy_driver_unregister(&at8035_driver);
- phy_driver_unregister(&at8030_driver);
+ return phy_drivers_unregister(at803x_driver,
+ ARRAY_SIZE(at803x_driver));
}
module_init(atheros_init);
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
index 84c7a39..ac55b08 100644
--- a/drivers/net/phy/bcm63xx.c
+++ b/drivers/net/phy/bcm63xx.c
@@ -78,7 +78,7 @@ static struct phy_driver bcm63xx_driver[] = {
.name = "Broadcom BCM63XX (1)",
/* ASYM_PAUSE bit is marked RO in datasheet, so don't cheat */
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
- .flags = PHY_HAS_INTERRUPT,
+ .flags = PHY_HAS_INTERRUPT | PHY_IS_INTERNAL,
.config_init = bcm63xx_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
@@ -91,7 +91,7 @@ static struct phy_driver bcm63xx_driver[] = {
.phy_id_mask = 0xfffffc00,
.name = "Broadcom BCM63XX (2)",
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
- .flags = PHY_HAS_INTERRUPT,
+ .flags = PHY_HAS_INTERRUPT | PHY_IS_INTERNAL,
.config_init = bcm63xx_config_init,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 202fe1f..2e91477 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -116,6 +116,8 @@
#define MII_M1011_PHY_STATUS_RESOLVED 0x0800
#define MII_M1011_PHY_STATUS_LINK 0x0400
+#define MII_M1116R_CONTROL_REG_MAC 21
+
MODULE_DESCRIPTION("Marvell PHY driver");
MODULE_AUTHOR("Andy Fleming");
@@ -372,6 +374,66 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
return m88e1121_config_aneg(phydev);
}
+static int m88e1510_config_aneg(struct phy_device *phydev)
+{
+ int err;
+
+ err = m88e1318_config_aneg(phydev);
+ if (err < 0)
+ return err;
+
+ return marvell_of_reg_init(phydev);
+}
+
+static int m88e1116r_config_init(struct phy_device *phydev)
+{
+ int temp;
+ int err;
+
+ temp = phy_read(phydev, MII_BMCR);
+ temp |= BMCR_RESET;
+ err = phy_write(phydev, MII_BMCR, temp);
+ if (err < 0)
+ return err;
+
+ mdelay(500);
+
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
+ if (err < 0)
+ return err;
+
+ temp = phy_read(phydev, MII_M1011_PHY_SCR);
+ temp |= (7 << 12); /* max number of gigabit attempts */
+ temp |= (1 << 11); /* enable downshift */
+ temp |= MII_M1011_PHY_SCR_AUTO_CROSS;
+ err = phy_write(phydev, MII_M1011_PHY_SCR, temp);
+ if (err < 0)
+ return err;
+
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 2);
+ if (err < 0)
+ return err;
+ temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC);
+ temp |= (1 << 5);
+ temp |= (1 << 4);
+ err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp);
+ if (err < 0)
+ return err;
+ err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0);
+ if (err < 0)
+ return err;
+
+ temp = phy_read(phydev, MII_BMCR);
+ temp |= BMCR_RESET;
+ err = phy_write(phydev, MII_BMCR, temp);
+ if (err < 0)
+ return err;
+
+ mdelay(500);
+
+ return 0;
+}
+
static int m88e1111_config_init(struct phy_device *phydev)
{
int err;
@@ -940,6 +1002,32 @@ static struct phy_driver marvell_drivers[] = {
.config_intr = &marvell_config_intr,
.driver = { .owner = THIS_MODULE },
},
+ {
+ .phy_id = MARVELL_PHY_ID_88E1116R,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E1116R",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &m88e1116r_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ },
+ {
+ .phy_id = MARVELL_PHY_ID_88E1510,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E1510",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &m88e1510_config_aneg,
+ .read_status = &marvell_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .did_interrupt = &m88e1121_did_interrupt,
+ .driver = { .owner = THIS_MODULE },
+ },
};
static int __init marvell_init(void)
@@ -958,15 +1046,17 @@ module_init(marvell_init);
module_exit(marvell_exit);
static struct mdio_device_id __maybe_unused marvell_tbl[] = {
- { 0x01410c60, 0xfffffff0 },
- { 0x01410c90, 0xfffffff0 },
- { 0x01410cc0, 0xfffffff0 },
- { 0x01410e10, 0xfffffff0 },
- { 0x01410cb0, 0xfffffff0 },
- { 0x01410cd0, 0xfffffff0 },
- { 0x01410e50, 0xfffffff0 },
- { 0x01410e30, 0xfffffff0 },
- { 0x01410e90, 0xfffffff0 },
+ { MARVELL_PHY_ID_88E1101, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1112, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1111, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1118, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1121R, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1145, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1149R, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1240, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
{ }
};
diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c
new file mode 100644
index 0000000..61d3f4e
--- /dev/null
+++ b/drivers/net/phy/mdio-sun4i.c
@@ -0,0 +1,194 @@
+/*
+ * Allwinner EMAC MDIO interface driver
+ *
+ * Copyright 2012-2013 Stefan Roese <sr@denx.de>
+ * Copyright 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * Based on the Linux driver provided by Allwinner:
+ * Copyright (C) 1997 Sten Wang
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/of_mdio.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define EMAC_MAC_MCMD_REG (0x00)
+#define EMAC_MAC_MADR_REG (0x04)
+#define EMAC_MAC_MWTD_REG (0x08)
+#define EMAC_MAC_MRDD_REG (0x0c)
+#define EMAC_MAC_MIND_REG (0x10)
+#define EMAC_MAC_SSRR_REG (0x14)
+
+#define MDIO_TIMEOUT (msecs_to_jiffies(100))
+
+struct sun4i_mdio_data {
+ void __iomem *membase;
+ struct regulator *regulator;
+};
+
+static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct sun4i_mdio_data *data = bus->priv;
+ unsigned long start_jiffies;
+ int value;
+
+ /* issue the phy address and reg */
+ writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG);
+ /* pull up the phy io line */
+ writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
+
+ /* Wait read complete */
+ start_jiffies = jiffies;
+ while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
+ if (time_after(start_jiffies,
+ start_jiffies + MDIO_TIMEOUT))
+ return -ETIMEDOUT;
+ msleep(1);
+ }
+
+ /* push down the phy io line */
+ writel(0x0, data->membase + EMAC_MAC_MCMD_REG);
+ /* and read data */
+ value = readl(data->membase + EMAC_MAC_MRDD_REG);
+
+ return value;
+}
+
+static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 value)
+{
+ struct sun4i_mdio_data *data = bus->priv;
+ unsigned long start_jiffies;
+
+ /* issue the phy address and reg */
+ writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG);
+ /* pull up the phy io line */
+ writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
+
+ /* Wait read complete */
+ start_jiffies = jiffies;
+ while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
+ if (time_after(start_jiffies,
+ start_jiffies + MDIO_TIMEOUT))
+ return -ETIMEDOUT;
+ msleep(1);
+ }
+
+ /* push down the phy io line */
+ writel(0x0, data->membase + EMAC_MAC_MCMD_REG);
+ /* and write data */
+ writel(value, data->membase + EMAC_MAC_MWTD_REG);
+
+ return 0;
+}
+
+static int sun4i_mdio_reset(struct mii_bus *bus)
+{
+ return 0;
+}
+
+static int sun4i_mdio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct mii_bus *bus;
+ struct sun4i_mdio_data *data;
+ int ret, i;
+
+ bus = mdiobus_alloc_size(sizeof(*data));
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "sun4i_mii_bus";
+ bus->read = &sun4i_mdio_read;
+ bus->write = &sun4i_mdio_write;
+ bus->reset = &sun4i_mdio_reset;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
+ bus->parent = &pdev->dev;
+
+ bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!bus->irq) {
+ ret = -ENOMEM;
+ goto err_out_free_mdiobus;
+ }
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ bus->irq[i] = PHY_POLL;
+
+ data = bus->priv;
+ data->membase = of_iomap(np, 0);
+ if (!data->membase) {
+ ret = -ENOMEM;
+ goto err_out_free_mdio_irq;
+ }
+
+ data->regulator = devm_regulator_get(&pdev->dev, "phy");
+ if (IS_ERR(data->regulator)) {
+ if (PTR_ERR(data->regulator) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ dev_info(&pdev->dev, "no regulator found\n");
+ } else {
+ ret = regulator_enable(data->regulator);
+ if (ret)
+ goto err_out_free_mdio_irq;
+ }
+
+ ret = of_mdiobus_register(bus, np);
+ if (ret < 0)
+ goto err_out_disable_regulator;
+
+ platform_set_drvdata(pdev, bus);
+
+ return 0;
+
+err_out_disable_regulator:
+ regulator_disable(data->regulator);
+err_out_free_mdio_irq:
+ kfree(bus->irq);
+err_out_free_mdiobus:
+ mdiobus_free(bus);
+ return ret;
+}
+
+static int sun4i_mdio_remove(struct platform_device *pdev)
+{
+ struct mii_bus *bus = platform_get_drvdata(pdev);
+
+ mdiobus_unregister(bus);
+ kfree(bus->irq);
+ mdiobus_free(bus);
+
+ return 0;
+}
+
+static const struct of_device_id sun4i_mdio_dt_ids[] = {
+ { .compatible = "allwinner,sun4i-mdio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sun4i_mdio_dt_ids);
+
+static struct platform_driver sun4i_mdio_driver = {
+ .probe = sun4i_mdio_probe,
+ .remove = sun4i_mdio_remove,
+ .driver = {
+ .name = "sun4i-mdio",
+ .of_match_table = sun4i_mdio_dt_ids,
+ },
+};
+
+module_platform_driver(sun4i_mdio_driver);
+
+MODULE_DESCRIPTION("Allwinner EMAC MDIO interface driver");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c14f147..10d058a 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -294,7 +294,8 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
cmd->duplex = phydev->duplex;
cmd->port = PORT_MII;
cmd->phy_address = phydev->addr;
- cmd->transceiver = XCVR_EXTERNAL;
+ cmd->transceiver = phy_is_internal(phydev) ?
+ XCVR_INTERNAL : XCVR_EXTERNAL;
cmd->autoneg = phydev->autoneg;
return 0;
@@ -419,8 +420,6 @@ out_unlock:
EXPORT_SYMBOL(phy_start_aneg);
-static void phy_change(struct work_struct *work);
-
/**
* phy_start_machine - start PHY state machine tracking
* @phydev: the phy_device struct
@@ -565,8 +564,6 @@ int phy_start_interrupts(struct phy_device *phydev)
{
int err = 0;
- INIT_WORK(&phydev->phy_queue, phy_change);
-
atomic_set(&phydev->irq_disable, 0);
if (request_irq(phydev->irq, phy_interrupt,
IRQF_SHARED,
@@ -623,7 +620,7 @@ EXPORT_SYMBOL(phy_stop_interrupts);
* phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes
* @work: work_struct that describes the work to be done
*/
-static void phy_change(struct work_struct *work)
+void phy_change(struct work_struct *work)
{
int err;
struct phy_device *phydev =
@@ -682,7 +679,7 @@ void phy_stop(struct phy_device *phydev)
if (PHY_HALTED == phydev->state)
goto out_unlock;
- if (phydev->irq != PHY_POLL) {
+ if (phy_interrupt_is_valid(phydev)) {
/* Disable PHY Interrupts */
phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
@@ -828,8 +825,9 @@ void phy_state_machine(struct work_struct *work)
break;
case PHY_RUNNING:
/* Only register a CHANGE if we are
- * polling */
- if (PHY_POLL == phydev->irq)
+ * polling or ignoring interrupts
+ */
+ if (!phy_interrupt_is_valid(phydev))
phydev->state = PHY_CHANGELINK;
break;
case PHY_CHANGELINK:
@@ -848,7 +846,7 @@ void phy_state_machine(struct work_struct *work)
phydev->adjust_link(phydev->attached_dev);
- if (PHY_POLL != phydev->irq)
+ if (phy_interrupt_is_valid(phydev))
err = phy_config_interrupt(phydev,
PHY_INTERRUPT_ENABLED);
break;
@@ -921,6 +919,14 @@ void phy_state_machine(struct work_struct *work)
schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ);
}
+void phy_mac_interrupt(struct phy_device *phydev, int new_link)
+{
+ cancel_work_sync(&phydev->phy_queue);
+ phydev->link = new_link;
+ schedule_work(&phydev->phy_queue);
+}
+EXPORT_SYMBOL(phy_mac_interrupt);
+
static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
int addr)
{
@@ -1044,7 +1050,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
idx = phy_find_setting(phydev->speed, phydev->duplex);
- if ((lp & adv & settings[idx].setting))
+ if (!(lp & adv & settings[idx].setting))
goto eee_exit;
if (clk_stop_enable) {
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 3657b4a..74630e9 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -189,6 +189,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
mutex_init(&dev->lock);
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
+ INIT_WORK(&dev->phy_queue, phy_change);
/* Request the appropriate module unconditionally; don't
bother trying to do so only if it isn't already loaded,
@@ -1009,10 +1010,16 @@ static int phy_probe(struct device *dev)
phydrv = to_phy_driver(drv);
phydev->drv = phydrv;
- /* Disable the interrupt if the PHY doesn't support it */
- if (!(phydrv->flags & PHY_HAS_INTERRUPT))
+ /* Disable the interrupt if the PHY doesn't support it
+ * but the interrupt is still a valid one
+ */
+ if (!(phydrv->flags & PHY_HAS_INTERRUPT) &&
+ phy_interrupt_is_valid(phydev))
phydev->irq = PHY_POLL;
+ if (phydrv->flags & PHY_IS_INTERNAL)
+ phydev->is_internal = true;
+
mutex_lock(&phydev->lock);
/* Start out supporting everything. Eventually,
diff --git a/drivers/net/phy/spi_ks8995.c b/drivers/net/phy/spi_ks8995.c
index d11c93e..f3bea13 100644
--- a/drivers/net/phy/spi_ks8995.c
+++ b/drivers/net/phy/spi_ks8995.c
@@ -354,19 +354,7 @@ static struct spi_driver ks8995_driver = {
.remove = ks8995_remove,
};
-static int __init ks8995_init(void)
-{
- pr_info(DRV_DESC " version " DRV_VERSION "\n");
-
- return spi_register_driver(&ks8995_driver);
-}
-module_init(ks8995_init);
-
-static void __exit ks8995_exit(void)
-{
- spi_unregister_driver(&ks8995_driver);
-}
-module_exit(ks8995_exit);
+module_spi_driver(ks8995_driver);
MODULE_DESCRIPTION(DRV_DESC);
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 3492b53..69b482b 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -44,18 +44,19 @@
#define MII_VSC8244_ISTAT_DUPLEX 0x1000
/* Vitesse Auxiliary Control/Status Register */
-#define MII_VSC8244_AUX_CONSTAT 0x1c
-#define MII_VSC8244_AUXCONSTAT_INIT 0x0000
-#define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020
-#define MII_VSC8244_AUXCONSTAT_SPEED 0x0018
-#define MII_VSC8244_AUXCONSTAT_GBIT 0x0010
-#define MII_VSC8244_AUXCONSTAT_100 0x0008
+#define MII_VSC8244_AUX_CONSTAT 0x1c
+#define MII_VSC8244_AUXCONSTAT_INIT 0x0000
+#define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020
+#define MII_VSC8244_AUXCONSTAT_SPEED 0x0018
+#define MII_VSC8244_AUXCONSTAT_GBIT 0x0010
+#define MII_VSC8244_AUXCONSTAT_100 0x0008
#define MII_VSC8221_AUXCONSTAT_INIT 0x0004 /* need to set this bit? */
#define MII_VSC8221_AUXCONSTAT_RESERVED 0x0004
#define PHY_ID_VSC8244 0x000fc6c0
#define PHY_ID_VSC8221 0x000fc550
+#define PHY_ID_VSC8211 0x000fc4b0
MODULE_DESCRIPTION("Vitesse PHY driver");
MODULE_AUTHOR("Kriston Carson");
@@ -100,9 +101,8 @@ static int vsc824x_config_init(struct phy_device *phydev)
static int vsc824x_ack_interrupt(struct phy_device *phydev)
{
int err = 0;
-
- /*
- * Don't bother to ACK the interrupts if interrupts
+
+ /* Don't bother to ACK the interrupts if interrupts
* are disabled. The 824x cannot clear the interrupts
* if they are disabled.
*/
@@ -122,8 +122,7 @@ static int vsc82xx_config_intr(struct phy_device *phydev)
MII_VSC8244_IMASK_MASK :
MII_VSC8221_IMASK_MASK);
else {
- /*
- * The Vitesse PHY cannot clear the interrupt
+ /* The Vitesse PHY cannot clear the interrupt
* once it has disabled them, so we clear them first
*/
err = phy_read(phydev, MII_VSC8244_ISTAT);
@@ -146,7 +145,8 @@ static int vsc8221_config_init(struct phy_device *phydev)
return err;
/* Perhaps we should set EXT_CON1 based on the interface?
- Options are 802.3Z SerDes or SGMII */
+ * Options are 802.3Z SerDes or SGMII
+ */
}
/* Vitesse 824x */
@@ -176,6 +176,19 @@ static struct phy_driver vsc82xx_driver[] = {
.ack_interrupt = &vsc824x_ack_interrupt,
.config_intr = &vsc82xx_config_intr,
.driver = { .owner = THIS_MODULE,},
+}, {
+ /* Vitesse 8211 */
+ .phy_id = PHY_ID_VSC8211,
+ .phy_id_mask = 0x000ffff0,
+ .name = "Vitesse VSC8211",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &vsc8221_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &vsc824x_ack_interrupt,
+ .config_intr = &vsc82xx_config_intr,
+ .driver = { .owner = THIS_MODULE,},
} };
static int __init vsc82xx_init(void)
@@ -196,6 +209,7 @@ module_exit(vsc82xx_exit);
static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
{ PHY_ID_VSC8244, 0x000fffc0 },
{ PHY_ID_VSC8221, 0x000ffff0 },
+ { PHY_ID_VSC8211, 0x000ffff0 },
{ }
};
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index bb07ba9..5f66e30 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -338,7 +338,7 @@ static void pppoe_flush_dev(struct net_device *dev)
static int pppoe_device_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
- struct net_device *dev = (struct net_device *)ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
/* Only look at sockets that are using this specific device. */
switch (event) {
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 7c43261..bff7e0b 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -525,31 +525,26 @@ static void team_set_no_mode(struct team *team)
team->mode = &__team_no_mode;
}
-static void __team_adjust_ops(struct team *team, int en_port_count)
+static void team_adjust_ops(struct team *team)
{
/*
* To avoid checks in rx/tx skb paths, ensure here that non-null and
* correct ops are always set.
*/
- if (!en_port_count || !team_is_mode_set(team) ||
+ if (!team->en_port_count || !team_is_mode_set(team) ||
!team->mode->ops->transmit)
team->ops.transmit = team_dummy_transmit;
else
team->ops.transmit = team->mode->ops->transmit;
- if (!en_port_count || !team_is_mode_set(team) ||
+ if (!team->en_port_count || !team_is_mode_set(team) ||
!team->mode->ops->receive)
team->ops.receive = team_dummy_receive;
else
team->ops.receive = team->mode->ops->receive;
}
-static void team_adjust_ops(struct team *team)
-{
- __team_adjust_ops(team, team->en_port_count);
-}
-
/*
* We can benefit from the fact that it's ensured no port is present
* at the time of mode change. Therefore no packets are in fly so there's no
@@ -725,9 +720,9 @@ static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb)
static void __team_queue_override_port_del(struct team *team,
struct team_port *port)
{
+ if (!port->queue_id)
+ return;
list_del_rcu(&port->qom_list);
- synchronize_rcu();
- INIT_LIST_HEAD(&port->qom_list);
}
static bool team_queue_override_port_has_gt_prio_than(struct team_port *port,
@@ -749,9 +744,8 @@ static void __team_queue_override_port_add(struct team *team,
struct list_head *qom_list;
struct list_head *node;
- if (!port->queue_id || !team_port_enabled(port))
+ if (!port->queue_id)
return;
-
qom_list = __team_get_qom_list(team, port->queue_id);
node = qom_list;
list_for_each_entry(cur, qom_list, qom_list) {
@@ -768,7 +762,7 @@ static void __team_queue_override_enabled_check(struct team *team)
bool enabled = false;
list_for_each_entry(port, &team->port_list, list) {
- if (!list_empty(&port->qom_list)) {
+ if (port->queue_id) {
enabled = true;
break;
}
@@ -780,14 +774,44 @@ static void __team_queue_override_enabled_check(struct team *team)
team->queue_override_enabled = enabled;
}
-static void team_queue_override_port_refresh(struct team *team,
- struct team_port *port)
+static void team_queue_override_port_prio_changed(struct team *team,
+ struct team_port *port)
{
+ if (!port->queue_id || team_port_enabled(port))
+ return;
__team_queue_override_port_del(team, port);
__team_queue_override_port_add(team, port);
__team_queue_override_enabled_check(team);
}
+static void team_queue_override_port_change_queue_id(struct team *team,
+ struct team_port *port,
+ u16 new_queue_id)
+{
+ if (team_port_enabled(port)) {
+ __team_queue_override_port_del(team, port);
+ port->queue_id = new_queue_id;
+ __team_queue_override_port_add(team, port);
+ __team_queue_override_enabled_check(team);
+ } else {
+ port->queue_id = new_queue_id;
+ }
+}
+
+static void team_queue_override_port_add(struct team *team,
+ struct team_port *port)
+{
+ __team_queue_override_port_add(team, port);
+ __team_queue_override_enabled_check(team);
+}
+
+static void team_queue_override_port_del(struct team *team,
+ struct team_port *port)
+{
+ __team_queue_override_port_del(team, port);
+ __team_queue_override_enabled_check(team);
+}
+
/****************
* Port handling
@@ -819,7 +843,7 @@ static void team_port_enable(struct team *team,
hlist_add_head_rcu(&port->hlist,
team_port_index_hash(team, port->index));
team_adjust_ops(team);
- team_queue_override_port_refresh(team, port);
+ team_queue_override_port_add(team, port);
if (team->ops.port_enabled)
team->ops.port_enabled(team, port);
}
@@ -848,14 +872,9 @@ static void team_port_disable(struct team *team,
hlist_del_rcu(&port->hlist);
__reconstruct_port_hlist(team, port->index);
port->index = -1;
- team_queue_override_port_refresh(team, port);
- __team_adjust_ops(team, team->en_port_count - 1);
- /*
- * Wait until readers see adjusted ops. This ensures that
- * readers never see team->en_port_count == 0
- */
- synchronize_rcu();
team->en_port_count--;
+ team_queue_override_port_del(team, port);
+ team_adjust_ops(team);
}
#define TEAM_VLAN_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | \
@@ -1092,8 +1111,8 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
}
port->index = -1;
- team_port_enable(team, port);
list_add_tail_rcu(&port->list, &team->port_list);
+ team_port_enable(team, port);
__team_compute_features(team);
__team_port_change_port_added(port, !!netif_carrier_ok(port_dev));
__team_options_change_check(team);
@@ -1163,8 +1182,7 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
team_port_set_orig_dev_addr(port);
dev_set_mtu(port_dev, port->orig.mtu);
- synchronize_rcu();
- kfree(port);
+ kfree_rcu(port, rcu);
netdev_info(dev, "Port device %s removed\n", portname);
__team_compute_features(team);
@@ -1259,9 +1277,12 @@ static int team_priority_option_set(struct team *team,
struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->info->port;
+ s32 priority = ctx->data.s32_val;
- port->priority = ctx->data.s32_val;
- team_queue_override_port_refresh(team, port);
+ if (port->priority == priority)
+ return 0;
+ port->priority = priority;
+ team_queue_override_port_prio_changed(team, port);
return 0;
}
@@ -1278,17 +1299,16 @@ static int team_queue_id_option_set(struct team *team,
struct team_gsetter_ctx *ctx)
{
struct team_port *port = ctx->info->port;
+ u16 new_queue_id = ctx->data.u32_val;
- if (port->queue_id == ctx->data.u32_val)
+ if (port->queue_id == new_queue_id)
return 0;
- if (ctx->data.u32_val >= team->dev->real_num_tx_queues)
+ if (new_queue_id >= team->dev->real_num_tx_queues)
return -EINVAL;
- port->queue_id = ctx->data.u32_val;
- team_queue_override_port_refresh(team, port);
+ team_queue_override_port_change_queue_id(team, port, new_queue_id);
return 0;
}
-
static const struct team_option team_options[] = {
{
.name = "mode",
@@ -2374,7 +2394,8 @@ static int team_nl_send_port_list_get(struct team *team, u32 portid, u32 seq,
bool incomplete;
int i;
- port = list_first_entry(&team->port_list, struct team_port, list);
+ port = list_first_entry_or_null(&team->port_list,
+ struct team_port, list);
start_again:
err = __send_and_alloc_skb(&skb, team, portid, send_func);
@@ -2402,8 +2423,8 @@ start_again:
err = team_nl_fill_one_port_get(skb, one_port);
if (err)
goto errout;
- } else {
- list_for_each_entry(port, &team->port_list, list) {
+ } else if (port) {
+ list_for_each_entry_from(port, &team->port_list, list) {
err = team_nl_fill_one_port_get(skb, port);
if (err) {
if (err == -EMSGSIZE) {
@@ -2647,7 +2668,7 @@ static void team_port_change_check(struct team_port *port, bool linkup)
static int team_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
- struct net_device *dev = (struct net_device *) ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct team_port *port;
port = team_port_get_rtnl(dev);
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index cdc31b5..829a9cd 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -112,9 +112,8 @@ static struct team_port *lb_hash_select_tx_port(struct team *team,
struct sk_buff *skb,
unsigned char hash)
{
- int port_index;
+ int port_index = team_num_to_port_index(team, hash);
- port_index = hash % team->en_port_count;
return team_get_port_by_index_rcu(team, port_index);
}
diff --git a/drivers/net/team/team_mode_random.c b/drivers/net/team/team_mode_random.c
index 5ca14d4..7f032e2 100644
--- a/drivers/net/team/team_mode_random.c
+++ b/drivers/net/team/team_mode_random.c
@@ -28,6 +28,8 @@ static bool rnd_transmit(struct team *team, struct sk_buff *skb)
port_index = random_N(team->en_port_count);
port = team_get_port_by_index_rcu(team, port_index);
+ if (unlikely(!port))
+ goto drop;
port = team_get_first_port_txable_rcu(team, port);
if (unlikely(!port))
goto drop;
diff --git a/drivers/net/team/team_mode_roundrobin.c b/drivers/net/team/team_mode_roundrobin.c
index d268e4d..5366585 100644
--- a/drivers/net/team/team_mode_roundrobin.c
+++ b/drivers/net/team/team_mode_roundrobin.c
@@ -30,8 +30,11 @@ static bool rr_transmit(struct team *team, struct sk_buff *skb)
struct team_port *port;
int port_index;
- port_index = rr_priv(team)->sent_packets++ % team->en_port_count;
+ port_index = team_num_to_port_index(team,
+ rr_priv(team)->sent_packets++);
port = team_get_port_by_index_rcu(team, port_index);
+ if (unlikely(!port))
+ goto drop;
port = team_get_first_port_txable_rcu(team, port);
if (unlikely(!port))
goto drop;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index f042b03..cea2fe4 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -352,7 +352,7 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb)
u32 numqueues = 0;
rcu_read_lock();
- numqueues = tun->numqueues;
+ numqueues = ACCESS_ONCE(tun->numqueues);
txq = skb_get_rxhash(skb);
if (txq) {
@@ -841,7 +841,7 @@ static const struct net_device_ops tap_netdev_ops = {
#endif
};
-static int tun_flow_init(struct tun_struct *tun)
+static void tun_flow_init(struct tun_struct *tun)
{
int i;
@@ -852,8 +852,6 @@ static int tun_flow_init(struct tun_struct *tun)
setup_timer(&tun->flow_gc_timer, tun_flow_cleanup, (unsigned long)tun);
mod_timer(&tun->flow_gc_timer,
round_jiffies_up(jiffies + tun->ageing_time));
-
- return 0;
}
static void tun_flow_uninit(struct tun_struct *tun)
@@ -1530,6 +1528,9 @@ static int tun_flags(struct tun_struct *tun)
if (tun->flags & TUN_TAP_MQ)
flags |= IFF_MULTI_QUEUE;
+ if (tun->flags & TUN_PERSIST)
+ flags |= IFF_PERSIST;
+
return flags;
}
@@ -1585,6 +1586,10 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
else
return -EINVAL;
+ if (!!(ifr->ifr_flags & IFF_MULTI_QUEUE) !=
+ !!(tun->flags & TUN_TAP_MQ))
+ return -EINVAL;
+
if (tun_not_capable(tun))
return -EPERM;
err = security_tun_dev_open(tun->security);
@@ -1655,10 +1660,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
goto err_free_dev;
tun_net_init(dev);
-
- err = tun_flow_init(tun);
- if (err < 0)
- goto err_free_dev;
+ tun_flow_init(tun);
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
TUN_USER_FEATURES;
@@ -2155,6 +2157,8 @@ static int tun_chr_open(struct inode *inode, struct file * file)
set_bit(SOCK_EXTERNALLY_ALLOCATED, &tfile->socket.flags);
INIT_LIST_HEAD(&tfile->next);
+ sock_set_flag(&tfile->sk, SOCK_ZEROCOPY);
+
return 0;
}
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..d84bfd4 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -67,7 +67,6 @@ config USB_KAWETH
config USB_PEGASUS
tristate "USB Pegasus/Pegasus-II based ethernet device support"
- select NET_CORE
select MII
---help---
Say Y here if you know you have Pegasus or Pegasus-II based adapter.
@@ -83,7 +82,6 @@ config USB_PEGASUS
config USB_RTL8150
tristate "USB RTL8150 based ethernet device support"
- select NET_CORE
select MII
help
Say Y here if you have RTL8150 based usb-ethernet adapter.
@@ -95,7 +93,6 @@ config USB_RTL8150
config USB_RTL8152
tristate "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
- select NET_CORE
select MII
help
This option adds support for Realtek RTL8152 based USB 2.0
@@ -106,7 +103,6 @@ config USB_RTL8152
config USB_USBNET
tristate "Multi-purpose USB Networking Framework"
- select NET_CORE
select MII
---help---
This driver supports several kinds of network links over USB,
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 078795f..04ee044 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -627,6 +627,12 @@ static const struct usb_device_id products [] = {
.driver_info = 0,
},
+/* Huawei E1820 - handled by qmi_wwan */
+{
+ USB_DEVICE_INTERFACE_NUMBER(HUAWEI_VENDOR_ID, 0x14ac, 1),
+ .driver_info = 0,
+},
+
/* Realtek RTL8152 Based USB 2.0 Ethernet Adapters */
#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE)
{
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index 0192073..6866eae 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -221,12 +221,9 @@ done:
memset(skb_put(skb, padlen), 0, padlen);
}
- netdev_dbg(
- dev->net,
- "Sending package with length %i and padding %i. Header: %02x:%02x:%02x:%02x:%02x:%02x.",
- content_len, padlen, header_start[0], header_start[1],
- header_start[2], header_start[3], header_start[4],
- header_start[5]);
+ netdev_dbg(dev->net,
+ "Sending package with length %i and padding %i. Header: %6phC.",
+ content_len, padlen, header_start);
return skb;
}
@@ -263,32 +260,23 @@ kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
sizeof(EXPECTED_UNKNOWN_HEADER_1)) || !memcmp(
header_start, EXPECTED_UNKNOWN_HEADER_2,
sizeof(EXPECTED_UNKNOWN_HEADER_2))) {
- netdev_dbg(
- dev->net,
- "Received expected unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n",
- header_start[0], header_start[1],
- header_start[2], header_start[3],
- header_start[4], header_start[5],
+ netdev_dbg(dev->net,
+ "Received expected unknown frame header: %6phC. Package length: %i\n",
+ header_start,
skb->len - KALMIA_HEADER_LENGTH);
}
else {
- netdev_err(
- dev->net,
- "Received unknown frame header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n",
- header_start[0], header_start[1],
- header_start[2], header_start[3],
- header_start[4], header_start[5],
+ netdev_err(dev->net,
+ "Received unknown frame header: %6phC. Package length: %i\n",
+ header_start,
skb->len - KALMIA_HEADER_LENGTH);
return 0;
}
}
else
- netdev_dbg(
- dev->net,
- "Received header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n",
- header_start[0], header_start[1], header_start[2],
- header_start[3], header_start[4], header_start[5],
- skb->len - KALMIA_HEADER_LENGTH);
+ netdev_dbg(dev->net,
+ "Received header: %6phC. Package length: %i\n",
+ header_start, skb->len - KALMIA_HEADER_LENGTH);
/* subtract start header and end header */
usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH);
@@ -310,12 +298,9 @@ kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
sizeof(HEADER_END_OF_USB_PACKET)) == 0);
if (!is_last) {
header_start = skb->data + ether_packet_length;
- netdev_dbg(
- dev->net,
- "End header: %02x:%02x:%02x:%02x:%02x:%02x. Package length: %i\n",
- header_start[0], header_start[1],
- header_start[2], header_start[3],
- header_start[4], header_start[5],
+ netdev_dbg(dev->net,
+ "End header: %6phC. Package length: %i\n",
+ header_start,
skb->len - KALMIA_HEADER_LENGTH);
}
}
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index cf887c2..d095d0d 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -519,6 +519,7 @@ static const struct usb_device_id products[] = {
/* 3. Combined interface devices matching on interface number */
{QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */
{QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */
+ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */
{QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
{QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
{QMI_FIXED_INTF(0x19d2, 0x0017, 3)},
@@ -582,6 +583,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
{QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */
{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */
+ {QMI_FIXED_INTF(0x1e2d, 0x12d1, 4)}, /* Cinterion PLxx */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 14e5198..d02bac8 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -11,7 +11,6 @@
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/version.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
@@ -1749,18 +1748,7 @@ static struct usb_driver rtl8152_driver = {
.resume = rtl8152_resume
};
-static int __init usb_rtl8152_init(void)
-{
- return usb_register(&rtl8152_driver);
-}
-
-static void __exit usb_rtl8152_exit(void)
-{
- usb_deregister(&rtl8152_driver);
-}
-
-module_init(usb_rtl8152_init);
-module_exit(usb_rtl8152_exit);
+module_usb_driver(rtl8152_driver);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index a491d3a..6cbdac6 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -130,19 +130,23 @@ struct rtl8150 {
struct usb_device *udev;
struct tasklet_struct tl;
struct net_device *netdev;
- struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
+ struct urb *rx_urb, *tx_urb, *intr_urb;
struct sk_buff *tx_skb, *rx_skb;
struct sk_buff *rx_skb_pool[RX_SKB_POOL_SIZE];
spinlock_t rx_pool_lock;
struct usb_ctrlrequest dr;
int intr_interval;
- __le16 rx_creg;
u8 *intr_buff;
u8 phy;
};
typedef struct rtl8150 rtl8150_t;
+struct async_req {
+ struct usb_ctrlrequest dr;
+ u16 rx_creg;
+};
+
static const char driver_name [] = "rtl8150";
/*
@@ -164,51 +168,47 @@ static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
indx, 0, data, size, 500);
}
-static void ctrl_callback(struct urb *urb)
+static void async_set_reg_cb(struct urb *urb)
{
- rtl8150_t *dev;
+ struct async_req *req = (struct async_req *)urb->context;
int status = urb->status;
- switch (status) {
- case 0:
- break;
- case -EINPROGRESS:
- break;
- case -ENOENT:
- break;
- default:
- if (printk_ratelimit())
- dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status);
- }
- dev = urb->context;
- clear_bit(RX_REG_SET, &dev->flags);
+ if (status < 0)
+ dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status);
+ kfree(req);
+ usb_free_urb(urb);
}
-static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size)
+static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg)
{
- int ret;
-
- if (test_bit(RX_REG_SET, &dev->flags))
- return -EAGAIN;
+ int res = -ENOMEM;
+ struct urb *async_urb;
+ struct async_req *req;
- dev->dr.bRequestType = RTL8150_REQT_WRITE;
- dev->dr.bRequest = RTL8150_REQ_SET_REGS;
- dev->dr.wValue = cpu_to_le16(indx);
- dev->dr.wIndex = 0;
- dev->dr.wLength = cpu_to_le16(size);
- dev->ctrl_urb->transfer_buffer_length = size;
- usb_fill_control_urb(dev->ctrl_urb, dev->udev,
- usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
- &dev->rx_creg, size, ctrl_callback, dev);
- if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) {
- if (ret == -ENODEV)
+ req = kmalloc(sizeof(struct async_req), GFP_ATOMIC);
+ if (req == NULL)
+ return res;
+ async_urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (async_urb == NULL) {
+ kfree(req);
+ return res;
+ }
+ req->rx_creg = cpu_to_le16(reg);
+ req->dr.bRequestType = RTL8150_REQT_WRITE;
+ req->dr.bRequest = RTL8150_REQ_SET_REGS;
+ req->dr.wIndex = 0;
+ req->dr.wValue = cpu_to_le16(indx);
+ req->dr.wLength = cpu_to_le16(size);
+ usb_fill_control_urb(async_urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0), (void *)&req->dr,
+ &req->rx_creg, size, async_set_reg_cb, req);
+ res = usb_submit_urb(async_urb, GFP_ATOMIC);
+ if (res) {
+ if (res == -ENODEV)
netif_device_detach(dev->netdev);
- dev_err(&dev->udev->dev,
- "control request submission failed: %d\n", ret);
- } else
- set_bit(RX_REG_SET, &dev->flags);
-
- return ret;
+ dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res);
+ }
+ return res;
}
static int read_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 * reg)
@@ -330,13 +330,6 @@ static int alloc_all_urbs(rtl8150_t * dev)
usb_free_urb(dev->tx_urb);
return 0;
}
- dev->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->ctrl_urb) {
- usb_free_urb(dev->rx_urb);
- usb_free_urb(dev->tx_urb);
- usb_free_urb(dev->intr_urb);
- return 0;
- }
return 1;
}
@@ -346,7 +339,6 @@ static void free_all_urbs(rtl8150_t * dev)
usb_free_urb(dev->rx_urb);
usb_free_urb(dev->tx_urb);
usb_free_urb(dev->intr_urb);
- usb_free_urb(dev->ctrl_urb);
}
static void unlink_all_urbs(rtl8150_t * dev)
@@ -354,7 +346,6 @@ static void unlink_all_urbs(rtl8150_t * dev)
usb_kill_urb(dev->rx_urb);
usb_kill_urb(dev->tx_urb);
usb_kill_urb(dev->intr_urb);
- usb_kill_urb(dev->ctrl_urb);
}
static inline struct sk_buff *pull_skb(rtl8150_t *dev)
@@ -629,7 +620,6 @@ static int enable_net_traffic(rtl8150_t * dev)
}
/* RCR bit7=1 attach Rx info at the end; =0 HW CRC (which is broken) */
rcr = 0x9e;
- dev->rx_creg = cpu_to_le16(rcr);
tcr = 0xd8;
cr = 0x0c;
if (!(rcr & 0x80))
@@ -662,20 +652,22 @@ static void rtl8150_tx_timeout(struct net_device *netdev)
static void rtl8150_set_multicast(struct net_device *netdev)
{
rtl8150_t *dev = netdev_priv(netdev);
+ u16 rx_creg = 0x9e;
+
netif_stop_queue(netdev);
if (netdev->flags & IFF_PROMISC) {
- dev->rx_creg |= cpu_to_le16(0x0001);
+ rx_creg |= 0x0001;
dev_info(&netdev->dev, "%s: promiscuous mode\n", netdev->name);
} else if (!netdev_mc_empty(netdev) ||
(netdev->flags & IFF_ALLMULTI)) {
- dev->rx_creg &= cpu_to_le16(0xfffe);
- dev->rx_creg |= cpu_to_le16(0x0002);
+ rx_creg &= 0xfffe;
+ rx_creg |= 0x0002;
dev_info(&netdev->dev, "%s: allmulti set\n", netdev->name);
} else {
/* ~RX_MULTICAST, ~RX_PROMISCUOUS */
- dev->rx_creg &= cpu_to_le16(0x00fc);
+ rx_creg &= 0x00fc;
}
- async_set_registers(dev, RCR, 2);
+ async_set_registers(dev, RCR, sizeof(rx_creg), rx_creg);
netif_wake_queue(netdev);
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index f95cb03..06ee82f 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1477,7 +1477,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
/* usbnet already took usb runtime pm, so have to enable the feature
* for usb interface, otherwise usb_autopm_get_interface may return
- * failure if USB_SUSPEND(RUNTIME_PM) is enabled.
+ * failure if RUNTIME_PM is enabled.
*/
if (!driver->supports_autosuspend) {
driver->supports_autosuspend = 1;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 177f911..da86652 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -379,12 +379,6 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
else
snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d");
- if (strchr(dev->name, '%')) {
- err = dev_alloc_name(dev, dev->name);
- if (err < 0)
- goto err_alloc_name;
- }
-
err = register_netdevice(dev);
if (err < 0)
goto err_register_dev;
@@ -404,7 +398,6 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
err_register_dev:
/* nothing to do */
-err_alloc_name:
err_configure_peer:
unregister_netdevice(peer);
return err;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 3c23fdc..c9e0038 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -28,7 +28,7 @@
#include <linux/slab.h>
#include <linux/cpu.h>
-static int napi_weight = 128;
+static int napi_weight = NAPI_POLL_WEIGHT;
module_param(napi_weight, int, 0444);
static bool csum = true, gso = true;
@@ -636,10 +636,11 @@ static int virtnet_open(struct net_device *dev)
struct virtnet_info *vi = netdev_priv(dev);
int i;
- for (i = 0; i < vi->curr_queue_pairs; i++) {
- /* Make sure we have some buffers: if oom use wq. */
- if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
- schedule_delayed_work(&vi->refill, 0);
+ for (i = 0; i < vi->max_queue_pairs; i++) {
+ if (i < vi->curr_queue_pairs)
+ /* Make sure we have some buffers: if oom use wq. */
+ if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
+ schedule_delayed_work(&vi->refill, 0);
virtnet_napi_enable(&vi->rq[i]);
}
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index ba81f3c..284c6c0 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -44,6 +44,8 @@
#define VXLAN_VERSION "0.1"
+#define PORT_HASH_BITS 8
+#define PORT_HASH_SIZE (1<<PORT_HASH_BITS)
#define VNI_HASH_BITS 10
#define VNI_HASH_SIZE (1<<VNI_HASH_BITS)
#define FDB_HASH_BITS 8
@@ -76,15 +78,25 @@ static bool log_ecn_error = true;
module_param(log_ecn_error, bool, 0644);
MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
-/* per-net private data for this module */
static unsigned int vxlan_net_id;
-struct vxlan_net {
- struct socket *sock; /* UDP encap socket */
+
+/* per UDP socket information */
+struct vxlan_sock {
+ struct hlist_node hlist;
+ struct rcu_head rcu;
+ struct work_struct del_work;
+ unsigned int refcnt;
+ struct socket *sock;
struct hlist_head vni_list[VNI_HASH_SIZE];
};
+/* per-network namespace private data for this module */
+struct vxlan_net {
+ struct list_head vxlan_list;
+ struct hlist_head sock_list[PORT_HASH_SIZE];
+};
+
struct vxlan_rdst {
- struct rcu_head rcu;
__be32 remote_ip;
__be16 remote_port;
u32 remote_vni;
@@ -106,7 +118,9 @@ struct vxlan_fdb {
/* Pseudo network device */
struct vxlan_dev {
- struct hlist_node hlist;
+ struct hlist_node hlist; /* vni hash table */
+ struct list_head next; /* vxlan's per namespace list */
+ struct vxlan_sock *vn_sock; /* listening socket */
struct net_device *dev;
struct vxlan_rdst default_dst; /* default destination */
__be32 saddr; /* source address */
@@ -135,19 +149,43 @@ struct vxlan_dev {
/* salt for hash table */
static u32 vxlan_salt __read_mostly;
-static inline struct hlist_head *vni_head(struct net *net, u32 id)
+/* Virtual Network hash table head */
+static inline struct hlist_head *vni_head(struct vxlan_sock *vs, u32 id)
+{
+ return &vs->vni_list[hash_32(id, VNI_HASH_BITS)];
+}
+
+/* Socket hash table head */
+static inline struct hlist_head *vs_head(struct net *net, __be16 port)
{
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
- return &vn->vni_list[hash_32(id, VNI_HASH_BITS)];
+ return &vn->sock_list[hash_32(ntohs(port), PORT_HASH_BITS)];
+}
+
+/* Find VXLAN socket based on network namespace and UDP port */
+static struct vxlan_sock *vxlan_find_port(struct net *net, __be16 port)
+{
+ struct vxlan_sock *vs;
+
+ hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) {
+ if (inet_sk(vs->sock->sk)->inet_sport == port)
+ return vs;
+ }
+ return NULL;
}
/* Look up VNI in a per net namespace table */
-static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id)
+static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id, __be16 port)
{
+ struct vxlan_sock *vs;
struct vxlan_dev *vxlan;
- hlist_for_each_entry_rcu(vxlan, vni_head(net, id), hlist) {
+ vs = vxlan_find_port(net, port);
+ if (!vs)
+ return NULL;
+
+ hlist_for_each_entry_rcu(vxlan, vni_head(vs, id), hlist) {
if (vxlan->default_dst.remote_vni == id)
return vxlan;
}
@@ -301,7 +339,7 @@ static inline struct hlist_head *vxlan_fdb_head(struct vxlan_dev *vxlan,
}
/* Look up Ethernet address in forwarding table */
-static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
+static struct vxlan_fdb *__vxlan_find_mac(struct vxlan_dev *vxlan,
const u8 *mac)
{
@@ -316,6 +354,18 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
return NULL;
}
+static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
+ const u8 *mac)
+{
+ struct vxlan_fdb *f;
+
+ f = __vxlan_find_mac(vxlan, mac);
+ if (f)
+ f->used = jiffies;
+
+ return f;
+}
+
/* Add/update destinations for multicast */
static int vxlan_fdb_append(struct vxlan_fdb *f,
__be32 ip, __be16 port, __u32 vni, __u32 ifindex)
@@ -353,7 +403,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
struct vxlan_fdb *f;
int notify = 0;
- f = vxlan_find_mac(vxlan, mac);
+ f = __vxlan_find_mac(vxlan, mac);
if (f) {
if (flags & NLM_F_EXCL) {
netdev_dbg(vxlan->dev,
@@ -553,19 +603,22 @@ skip:
/* Watch incoming packets to learn mapping between Ethernet address
* and Tunnel endpoint.
+ * Return true if packet is bogus and should be droppped.
*/
-static void vxlan_snoop(struct net_device *dev,
+static bool vxlan_snoop(struct net_device *dev,
__be32 src_ip, const u8 *src_mac)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_fdb *f;
- int err;
f = vxlan_find_mac(vxlan, src_mac);
if (likely(f)) {
- f->used = jiffies;
if (likely(f->remote.remote_ip == src_ip))
- return;
+ return false;
+
+ /* Don't migrate static entries, drop packets */
+ if (f->state & NUD_NOARP)
+ return true;
if (net_ratelimit())
netdev_info(dev,
@@ -577,14 +630,19 @@ static void vxlan_snoop(struct net_device *dev,
} else {
/* learned new entry */
spin_lock(&vxlan->hash_lock);
- err = vxlan_fdb_create(vxlan, src_mac, src_ip,
- NUD_REACHABLE,
- NLM_F_EXCL|NLM_F_CREATE,
- vxlan->dst_port,
- vxlan->default_dst.remote_vni,
- 0, NTF_SELF);
+
+ /* close off race between vxlan_flush and incoming packets */
+ if (netif_running(dev))
+ vxlan_fdb_create(vxlan, src_mac, src_ip,
+ NUD_REACHABLE,
+ NLM_F_EXCL|NLM_F_CREATE,
+ vxlan->dst_port,
+ vxlan->default_dst.remote_vni,
+ 0, NTF_SELF);
spin_unlock(&vxlan->hash_lock);
}
+
+ return false;
}
@@ -592,20 +650,18 @@ static void vxlan_snoop(struct net_device *dev,
static bool vxlan_group_used(struct vxlan_net *vn,
const struct vxlan_dev *this)
{
- const struct vxlan_dev *vxlan;
- unsigned h;
+ struct vxlan_dev *vxlan;
- for (h = 0; h < VNI_HASH_SIZE; ++h)
- hlist_for_each_entry(vxlan, &vn->vni_list[h], hlist) {
- if (vxlan == this)
- continue;
+ list_for_each_entry(vxlan, &vn->vxlan_list, next) {
+ if (vxlan == this)
+ continue;
- if (!netif_running(vxlan->dev))
- continue;
+ if (!netif_running(vxlan->dev))
+ continue;
- if (vxlan->default_dst.remote_ip == this->default_dst.remote_ip)
- return true;
- }
+ if (vxlan->default_dst.remote_ip == this->default_dst.remote_ip)
+ return true;
+ }
return false;
}
@@ -615,7 +671,7 @@ static int vxlan_join_group(struct net_device *dev)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
- struct sock *sk = vn->sock->sk;
+ struct sock *sk = vxlan->vn_sock->sock->sk;
struct ip_mreqn mreq = {
.imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
.imr_ifindex = vxlan->default_dst.remote_ifindex,
@@ -643,7 +699,7 @@ static int vxlan_leave_group(struct net_device *dev)
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
int err = 0;
- struct sock *sk = vn->sock->sk;
+ struct sock *sk = vxlan->vn_sock->sock->sk;
struct ip_mreqn mreq = {
.imr_multiaddr.s_addr = vxlan->default_dst.remote_ip,
.imr_ifindex = vxlan->default_dst.remote_ifindex,
@@ -670,6 +726,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
struct vxlanhdr *vxh;
struct vxlan_dev *vxlan;
struct pcpu_tstats *stats;
+ __be16 port;
__u32 vni;
int err;
@@ -693,9 +750,11 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
/* Is this VNI defined? */
vni = ntohl(vxh->vx_vni) >> 8;
- vxlan = vxlan_find_vni(sock_net(sk), vni);
+ port = inet_sk(sk)->inet_sport;
+ vxlan = vxlan_find_vni(sock_net(sk), vni, port);
if (!vxlan) {
- netdev_dbg(skb->dev, "unknown vni %d\n", vni);
+ netdev_dbg(skb->dev, "unknown vni %d port %u\n",
+ vni, ntohs(port));
goto drop;
}
@@ -716,8 +775,9 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
vxlan->dev->dev_addr) == 0)
goto drop;
- if (vxlan->flags & VXLAN_F_LEARN)
- vxlan_snoop(skb->dev, oip->saddr, eth_hdr(skb)->h_source);
+ if ((vxlan->flags & VXLAN_F_LEARN) &&
+ vxlan_snoop(skb->dev, oip->saddr, eth_hdr(skb)->h_source))
+ goto drop;
__skb_tunnel_rx(skb, vxlan->dev);
skb_reset_network_header(skb);
@@ -875,7 +935,7 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
return false;
}
-static void vxlan_sock_free(struct sk_buff *skb)
+static void vxlan_sock_put(struct sk_buff *skb)
{
sock_put(skb->sk);
}
@@ -883,13 +943,13 @@ static void vxlan_sock_free(struct sk_buff *skb)
/* On transmit, associate with the tunnel socket */
static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb)
{
- struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
- struct sock *sk = vn->sock->sk;
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct sock *sk = vxlan->vn_sock->sock->sk;
skb_orphan(skb);
sock_hold(sk);
skb->sk = sk;
- skb->destructor = vxlan_sock_free;
+ skb->destructor = vxlan_sock_put;
}
/* Compute source port for outgoing packet
@@ -961,7 +1021,6 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
struct vxlan_dev *vxlan = netdev_priv(dev);
struct rtable *rt;
const struct iphdr *old_iph;
- struct iphdr *iph;
struct vxlanhdr *vxh;
struct udphdr *uh;
struct flowi4 fl4;
@@ -970,6 +1029,7 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
u32 vni;
__be16 df = 0;
__u8 tos, ttl;
+ int err;
dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port;
vni = rdst->remote_vni;
@@ -1031,19 +1091,12 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
struct vxlan_dev *dst_vxlan;
ip_rt_put(rt);
- dst_vxlan = vxlan_find_vni(dev_net(dev), vni);
+ dst_vxlan = vxlan_find_vni(dev_net(dev), vni, dst_port);
if (!dst_vxlan)
goto tx_error;
vxlan_encap_bypass(skb, vxlan, dst_vxlan);
return NETDEV_TX_OK;
}
-
- memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
- IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
- IPSKB_REROUTED);
- skb_dst_drop(skb);
- skb_dst_set(skb, &rt->dst);
-
vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
vxh->vx_flags = htonl(VXLAN_FLAGS);
vxh->vx_vni = htonl(vni << 8);
@@ -1058,27 +1111,18 @@ static netdev_tx_t vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
uh->len = htons(skb->len);
uh->check = 0;
- __skb_push(skb, sizeof(*iph));
- skb_reset_network_header(skb);
- iph = ip_hdr(skb);
- iph->version = 4;
- iph->ihl = sizeof(struct iphdr) >> 2;
- iph->frag_off = df;
- iph->protocol = IPPROTO_UDP;
- iph->tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
- iph->daddr = dst;
- iph->saddr = fl4.saddr;
- iph->ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
- tunnel_ip_select_ident(skb, old_iph, &rt->dst);
-
- nf_reset(skb);
-
vxlan_set_owner(dev, skb);
if (handle_offloads(skb))
goto drop;
- iptunnel_xmit(skb, dev);
+ tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
+ ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
+
+ err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, dst,
+ IPPROTO_UDP, tos, ttl, df);
+ iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
+
return NETDEV_TX_OK;
drop:
@@ -1140,9 +1184,11 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
struct sk_buff *skb1;
skb1 = skb_clone(skb, GFP_ATOMIC);
- rc1 = vxlan_xmit_one(skb1, dev, rdst, did_rsc);
- if (rc == NETDEV_TX_OK)
- rc = rc1;
+ if (skb1) {
+ rc1 = vxlan_xmit_one(skb1, dev, rdst, did_rsc);
+ if (rc == NETDEV_TX_OK)
+ rc = rc1;
+ }
}
rc1 = vxlan_xmit_one(skb, dev, rdst0, did_rsc);
@@ -1219,7 +1265,7 @@ static int vxlan_open(struct net_device *dev)
/* Purge the forwarding table */
static void vxlan_flush(struct vxlan_dev *vxlan)
{
- unsigned h;
+ unsigned int h;
spin_lock_bh(&vxlan->hash_lock);
for (h = 0; h < FDB_HASH_SIZE; ++h) {
@@ -1283,7 +1329,7 @@ static void vxlan_free(struct net_device *dev)
static void vxlan_setup(struct net_device *dev)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
- unsigned h;
+ unsigned int h;
int low, high;
eth_hw_addr_random(dev);
@@ -1306,6 +1352,7 @@ static void vxlan_setup(struct net_device *dev)
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+ INIT_LIST_HEAD(&vxlan->next);
spin_lock_init(&vxlan->hash_lock);
init_timer_deferrable(&vxlan->age_timer);
@@ -1390,11 +1437,78 @@ static const struct ethtool_ops vxlan_ethtool_ops = {
.get_link = ethtool_op_get_link,
};
+static void vxlan_del_work(struct work_struct *work)
+{
+ struct vxlan_sock *vs = container_of(work, struct vxlan_sock, del_work);
+
+ sk_release_kernel(vs->sock->sk);
+ kfree_rcu(vs, rcu);
+}
+
+/* Create new listen socket if needed */
+static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port)
+{
+ struct vxlan_sock *vs;
+ struct sock *sk;
+ struct sockaddr_in vxlan_addr = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_ANY),
+ };
+ int rc;
+ unsigned int h;
+
+ vs = kmalloc(sizeof(*vs), GFP_KERNEL);
+ if (!vs)
+ return ERR_PTR(-ENOMEM);
+
+ for (h = 0; h < VNI_HASH_SIZE; ++h)
+ INIT_HLIST_HEAD(&vs->vni_list[h]);
+
+ INIT_WORK(&vs->del_work, vxlan_del_work);
+
+ /* Create UDP socket for encapsulation receive. */
+ rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vs->sock);
+ if (rc < 0) {
+ pr_debug("UDP socket create failed\n");
+ kfree(vs);
+ return ERR_PTR(rc);
+ }
+
+ /* Put in proper namespace */
+ sk = vs->sock->sk;
+ sk_change_net(sk, net);
+
+ vxlan_addr.sin_port = port;
+
+ rc = kernel_bind(vs->sock, (struct sockaddr *) &vxlan_addr,
+ sizeof(vxlan_addr));
+ if (rc < 0) {
+ pr_debug("bind for UDP socket %pI4:%u (%d)\n",
+ &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
+ sk_release_kernel(sk);
+ kfree(vs);
+ return ERR_PTR(rc);
+ }
+
+ /* Disable multicast loopback */
+ inet_sk(sk)->mc_loop = 0;
+
+ /* Mark socket as an encapsulation socket. */
+ udp_sk(sk)->encap_type = 1;
+ udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv;
+ udp_encap_enable();
+
+ vs->refcnt = 1;
+ return vs;
+}
+
static int vxlan_newlink(struct net *net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
+ struct vxlan_net *vn = net_generic(net, vxlan_net_id);
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_rdst *dst = &vxlan->default_dst;
+ struct vxlan_sock *vs;
__u32 vni;
int err;
@@ -1402,10 +1516,6 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
return -EINVAL;
vni = nla_get_u32(data[IFLA_VXLAN_ID]);
- if (vxlan_find_vni(net, vni)) {
- pr_info("duplicate VNI %u\n", vni);
- return -EEXIST;
- }
dst->remote_vni = vni;
if (data[IFLA_VXLAN_GROUP])
@@ -1471,22 +1581,58 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
if (data[IFLA_VXLAN_PORT])
vxlan->dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]);
+ if (vxlan_find_vni(net, vni, vxlan->dst_port)) {
+ pr_info("duplicate VNI %u\n", vni);
+ return -EEXIST;
+ }
+
+ vs = vxlan_find_port(net, vxlan->dst_port);
+ if (vs)
+ ++vs->refcnt;
+ else {
+ /* Drop lock because socket create acquires RTNL lock */
+ rtnl_unlock();
+ vs = vxlan_socket_create(net, vxlan->dst_port);
+ rtnl_lock();
+ if (IS_ERR(vs))
+ return PTR_ERR(vs);
+
+ hlist_add_head_rcu(&vs->hlist, vs_head(net, vxlan->dst_port));
+ }
+ vxlan->vn_sock = vs;
+
SET_ETHTOOL_OPS(dev, &vxlan_ethtool_ops);
err = register_netdevice(dev);
- if (!err)
- hlist_add_head_rcu(&vxlan->hlist, vni_head(net, dst->remote_vni));
+ if (err) {
+ if (--vs->refcnt == 0) {
+ rtnl_unlock();
+ sk_release_kernel(vs->sock->sk);
+ kfree(vs);
+ rtnl_lock();
+ }
+ return err;
+ }
- return err;
+ list_add(&vxlan->next, &vn->vxlan_list);
+ hlist_add_head_rcu(&vxlan->hlist, vni_head(vs, vni));
+
+ return 0;
}
static void vxlan_dellink(struct net_device *dev, struct list_head *head)
{
struct vxlan_dev *vxlan = netdev_priv(dev);
+ struct vxlan_sock *vs = vxlan->vn_sock;
hlist_del_rcu(&vxlan->hlist);
-
+ list_del(&vxlan->next);
unregister_netdevice_queue(dev, head);
+
+ if (--vs->refcnt == 0) {
+ hlist_del_rcu(&vs->hlist);
+ schedule_work(&vs->del_work);
+ }
}
static size_t vxlan_get_size(const struct net_device *dev)
@@ -1572,46 +1718,12 @@ static struct rtnl_link_ops vxlan_link_ops __read_mostly = {
static __net_init int vxlan_init_net(struct net *net)
{
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
- struct sock *sk;
- struct sockaddr_in vxlan_addr = {
- .sin_family = AF_INET,
- .sin_addr.s_addr = htonl(INADDR_ANY),
- };
- int rc;
- unsigned h;
-
- /* Create UDP socket for encapsulation receive. */
- rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vn->sock);
- if (rc < 0) {
- pr_debug("UDP socket create failed\n");
- return rc;
- }
- /* Put in proper namespace */
- sk = vn->sock->sk;
- sk_change_net(sk, net);
-
- vxlan_addr.sin_port = htons(vxlan_port);
-
- rc = kernel_bind(vn->sock, (struct sockaddr *) &vxlan_addr,
- sizeof(vxlan_addr));
- if (rc < 0) {
- pr_debug("bind for UDP socket %pI4:%u (%d)\n",
- &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
- sk_release_kernel(sk);
- vn->sock = NULL;
- return rc;
- }
-
- /* Disable multicast loopback */
- inet_sk(sk)->mc_loop = 0;
+ unsigned int h;
- /* Mark socket as an encapsulation socket. */
- udp_sk(sk)->encap_type = 1;
- udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv;
- udp_encap_enable();
+ INIT_LIST_HEAD(&vn->vxlan_list);
- for (h = 0; h < VNI_HASH_SIZE; ++h)
- INIT_HLIST_HEAD(&vn->vni_list[h]);
+ for (h = 0; h < PORT_HASH_SIZE; ++h)
+ INIT_HLIST_HEAD(&vn->sock_list[h]);
return 0;
}
@@ -1620,18 +1732,11 @@ static __net_exit void vxlan_exit_net(struct net *net)
{
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
struct vxlan_dev *vxlan;
- unsigned h;
rtnl_lock();
- for (h = 0; h < VNI_HASH_SIZE; ++h)
- hlist_for_each_entry(vxlan, &vn->vni_list[h], hlist)
- dev_close(vxlan->dev);
+ list_for_each_entry(vxlan, &vn->vxlan_list, next)
+ dev_close(vxlan->dev);
rtnl_unlock();
-
- if (vn->sock) {
- sk_release_kernel(vn->sock->sk);
- vn->sock = NULL;
- }
}
static struct pernet_operations vxlan_net_ops = {
@@ -1662,7 +1767,7 @@ out2:
out1:
return rc;
}
-module_init(vxlan_init_module);
+late_initcall(vxlan_init_module);
static void __exit vxlan_cleanup_module(void)
{
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 147614e..70ac599 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -477,7 +477,7 @@ static void dlci_setup(struct net_device *dev)
static int dlci_dev_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
- struct net_device *dev = (struct net_device *) ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev_net(dev) != &init_net)
return NOTIFY_DONE;
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index a0a932c..9c33ca9 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -99,7 +99,7 @@ static inline void hdlc_proto_stop(struct net_device *dev)
static int hdlc_device_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
hdlc_device *hdlc;
unsigned long flags;
int on;
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index fc9d11d..e7bbdb7 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -1384,7 +1384,6 @@ static int hss_remove_one(struct platform_device *pdev)
unregister_hdlc_device(port->netdev);
free_netdev(port->netdev);
npe_release(port->npe);
- platform_set_drvdata(pdev, NULL);
kfree(port);
return 0;
}
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index a73b49e..a33a46f 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -370,7 +370,7 @@ static int lapbeth_device_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct lapbethdev *lapbeth;
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
if (dev_net(dev) != &init_net)
return NOTIFY_DONE;
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index 8e8bcc7a..e9bc9e6 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -185,7 +185,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
err_free_hw:
ieee80211_free_hw(hw);
- platform_set_drvdata(pdev, NULL);
err_iounmap:
iounmap(mem);
err_out:
@@ -221,7 +220,6 @@ static int ath_ahb_remove(struct platform_device *pdev)
ath5k_deinit_ah(ah);
iounmap(ah->iobase);
- platform_set_drvdata(pdev, NULL);
ieee80211_free_hw(hw);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index d1ff3c2..072e4b5 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -150,7 +150,6 @@ static int ath_ahb_probe(struct platform_device *pdev)
free_irq(irq, sc);
err_free_hw:
ieee80211_free_hw(hw);
- platform_set_drvdata(pdev, NULL);
return ret;
}
@@ -164,7 +163,6 @@ static int ath_ahb_remove(struct platform_device *pdev)
ath9k_deinit_device(sc);
free_irq(sc->irq, sc);
ieee80211_free_hw(sc->hw);
- platform_set_drvdata(pdev, NULL);
}
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 2721f52..87454f6 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -69,7 +69,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
return -EFAULT;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &mask))
+ if (kstrtoul(buf, 0, &mask))
return -EINVAL;
common->debug_mask = mask;
@@ -114,7 +114,7 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use
return -EFAULT;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &mask))
+ if (kstrtoul(buf, 0, &mask))
return -EINVAL;
ah->txchainmask = mask;
@@ -157,7 +157,7 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use
return -EFAULT;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &mask))
+ if (kstrtoul(buf, 0, &mask))
return -EINVAL;
ah->rxchainmask = mask;
@@ -244,7 +244,7 @@ static ssize_t write_file_ani(struct file *file,
return -EFAULT;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &ani))
+ if (kstrtoul(buf, 0, &ani))
return -EINVAL;
if (ani < 0 || ani > 1)
@@ -300,7 +300,7 @@ static ssize_t write_file_ant_diversity(struct file *file,
goto exit;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &antenna_diversity))
+ if (kstrtoul(buf, 0, &antenna_diversity))
return -EINVAL;
common->antenna_diversity = !!antenna_diversity;
@@ -1270,7 +1270,7 @@ static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
return -EFAULT;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &regidx))
+ if (kstrtoul(buf, 0, &regidx))
return -EINVAL;
sc->debug.regidx = regidx;
@@ -1315,7 +1315,7 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
return -EFAULT;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &regval))
+ if (kstrtoul(buf, 0, &regval))
return -EINVAL;
ath9k_ps_wakeup(sc);
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c
index b7611b7..3c6e413 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
@@ -96,7 +96,7 @@ static ssize_t write_file_dfs(struct file *file, const char __user *user_buf,
return -EFAULT;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &val))
+ if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val == DFS_STATS_RESET_MAGIC)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
index 87110de5..d08ef24 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -471,7 +471,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
return -EFAULT;
buf[len] = '\0';
- if (strict_strtoul(buf, 0, &mask))
+ if (kstrtoul(buf, 0, &mask))
return -EINVAL;
common->debug_mask = mask;
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index 866ce6c..9581d07 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -3119,7 +3119,7 @@ il3945_store_debug_level(struct device *d, struct device_attribute *attr,
unsigned long val;
int ret;
- ret = strict_strtoul(buf, 0, &val);
+ ret = kstrtoul(buf, 0, &val);
if (ret)
IL_INFO("%s is not in hex or decimal form.\n", buf);
else
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index d287fd2..b9b2bb5 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -4585,7 +4585,7 @@ il4965_store_debug_level(struct device *d, struct device_attribute *attr,
unsigned long val;
int ret;
- ret = strict_strtoul(buf, 0, &val);
+ ret = kstrtoul(buf, 0, &val);
if (ret)
IL_ERR("%s is not in hex or decimal form.\n", buf);
else
@@ -4632,7 +4632,7 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr,
unsigned long val;
int ret;
- ret = strict_strtoul(buf, 10, &val);
+ ret = kstrtoul(buf, 10, &val);
if (ret)
IL_INFO("%s is not in decimal form.\n", buf);
else {
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 3e81264..efae07e 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -240,7 +240,7 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
memset(&mesh_access, 0, sizeof(mesh_access));
mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
- if (!strict_strtoul(buf, 10, &retry_limit))
+ if (!kstrtoul(buf, 10, &retry_limit))
return -ENOTSUPP;
if (retry_limit > 15)
return -ENOTSUPP;
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index af59dd5..8053f77 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -1817,7 +1817,7 @@ static ssize_t rtl_store_debug_level(struct device *d,
unsigned long val;
int ret;
- ret = strict_strtoul(buf, 0, &val);
+ ret = kstrtoul(buf, 0, &val);
if (ret) {
printk(KERN_DEBUG "%s is not in hex or decimal form.\n", buf);
} else {
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 9d7f172..8a4d77e 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -57,8 +57,12 @@ struct xenvif {
u8 fe_dev_addr[6];
- /* Physical parameters of the comms window. */
- unsigned int irq;
+ /* When feature-split-event-channels = 0, tx_irq = rx_irq. */
+ unsigned int tx_irq;
+ unsigned int rx_irq;
+ /* Only used when feature-split-event-channels = 1 */
+ char tx_irq_name[IFNAMSIZ+4]; /* DEVNAME-tx */
+ char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */
/* List of frontends to notify after a batch of frames sent. */
struct list_head notify_list;
@@ -113,13 +117,15 @@ struct xenvif *xenvif_alloc(struct device *parent,
unsigned int handle);
int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn);
+ unsigned long rx_ring_ref, unsigned int tx_evtchn,
+ unsigned int rx_evtchn);
void xenvif_disconnect(struct xenvif *vif);
void xenvif_get(struct xenvif *vif);
void xenvif_put(struct xenvif *vif);
int xenvif_xenbus_init(void);
+void xenvif_xenbus_fini(void);
int xenvif_schedulable(struct xenvif *vif);
@@ -157,4 +163,6 @@ void xenvif_carrier_off(struct xenvif *vif);
/* Returns number of ring slots required to send an skb to the frontend */
unsigned int xen_netbk_count_skb_slots(struct xenvif *vif, struct sk_buff *skb);
+extern bool separate_tx_rx_irq;
+
#endif /* __XEN_NETBACK__COMMON_H__ */
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index d984141..087d2db 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -60,21 +60,39 @@ static int xenvif_rx_schedulable(struct xenvif *vif)
return xenvif_schedulable(vif) && !xen_netbk_rx_ring_full(vif);
}
-static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
+static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id)
{
struct xenvif *vif = dev_id;
if (vif->netbk == NULL)
- return IRQ_NONE;
+ return IRQ_HANDLED;
xen_netbk_schedule_xenvif(vif);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id)
+{
+ struct xenvif *vif = dev_id;
+
+ if (vif->netbk == NULL)
+ return IRQ_HANDLED;
+
if (xenvif_rx_schedulable(vif))
netif_wake_queue(vif->dev);
return IRQ_HANDLED;
}
+static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
+{
+ xenvif_tx_interrupt(irq, dev_id);
+ xenvif_rx_interrupt(irq, dev_id);
+
+ return IRQ_HANDLED;
+}
+
static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct xenvif *vif = netdev_priv(dev);
@@ -125,13 +143,17 @@ static struct net_device_stats *xenvif_get_stats(struct net_device *dev)
static void xenvif_up(struct xenvif *vif)
{
xen_netbk_add_xenvif(vif);
- enable_irq(vif->irq);
+ enable_irq(vif->tx_irq);
+ if (vif->tx_irq != vif->rx_irq)
+ enable_irq(vif->rx_irq);
xen_netbk_check_rx_xenvif(vif);
}
static void xenvif_down(struct xenvif *vif)
{
- disable_irq(vif->irq);
+ disable_irq(vif->tx_irq);
+ if (vif->tx_irq != vif->rx_irq)
+ disable_irq(vif->rx_irq);
del_timer_sync(&vif->credit_timeout);
xen_netbk_deschedule_xenvif(vif);
xen_netbk_remove_xenvif(vif);
@@ -308,25 +330,52 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
}
int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
- unsigned long rx_ring_ref, unsigned int evtchn)
+ unsigned long rx_ring_ref, unsigned int tx_evtchn,
+ unsigned int rx_evtchn)
{
int err = -ENOMEM;
/* Already connected through? */
- if (vif->irq)
+ if (vif->tx_irq)
return 0;
+ __module_get(THIS_MODULE);
+
err = xen_netbk_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
if (err < 0)
goto err;
- err = bind_interdomain_evtchn_to_irqhandler(
- vif->domid, evtchn, xenvif_interrupt, 0,
- vif->dev->name, vif);
- if (err < 0)
- goto err_unmap;
- vif->irq = err;
- disable_irq(vif->irq);
+ if (tx_evtchn == rx_evtchn) {
+ /* feature-split-event-channels == 0 */
+ err = bind_interdomain_evtchn_to_irqhandler(
+ vif->domid, tx_evtchn, xenvif_interrupt, 0,
+ vif->dev->name, vif);
+ if (err < 0)
+ goto err_unmap;
+ vif->tx_irq = vif->rx_irq = err;
+ disable_irq(vif->tx_irq);
+ } else {
+ /* feature-split-event-channels == 1 */
+ snprintf(vif->tx_irq_name, sizeof(vif->tx_irq_name),
+ "%s-tx", vif->dev->name);
+ err = bind_interdomain_evtchn_to_irqhandler(
+ vif->domid, tx_evtchn, xenvif_tx_interrupt, 0,
+ vif->tx_irq_name, vif);
+ if (err < 0)
+ goto err_unmap;
+ vif->tx_irq = err;
+ disable_irq(vif->tx_irq);
+
+ snprintf(vif->rx_irq_name, sizeof(vif->rx_irq_name),
+ "%s-rx", vif->dev->name);
+ err = bind_interdomain_evtchn_to_irqhandler(
+ vif->domid, rx_evtchn, xenvif_rx_interrupt, 0,
+ vif->rx_irq_name, vif);
+ if (err < 0)
+ goto err_tx_unbind;
+ vif->rx_irq = err;
+ disable_irq(vif->rx_irq);
+ }
xenvif_get(vif);
@@ -340,9 +389,13 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
rtnl_unlock();
return 0;
+err_tx_unbind:
+ unbind_from_irqhandler(vif->tx_irq, vif);
+ vif->tx_irq = 0;
err_unmap:
xen_netbk_unmap_frontend_rings(vif);
err:
+ module_put(THIS_MODULE);
return err;
}
@@ -360,18 +413,37 @@ void xenvif_carrier_off(struct xenvif *vif)
void xenvif_disconnect(struct xenvif *vif)
{
+ /* Disconnect funtion might get called by generic framework
+ * even before vif connects, so we need to check if we really
+ * need to do a module_put.
+ */
+ int need_module_put = 0;
+
if (netif_carrier_ok(vif->dev))
xenvif_carrier_off(vif);
atomic_dec(&vif->refcnt);
wait_event(vif->waiting_to_free, atomic_read(&vif->refcnt) == 0);
- if (vif->irq)
- unbind_from_irqhandler(vif->irq, vif);
+ if (vif->tx_irq) {
+ if (vif->tx_irq == vif->rx_irq)
+ unbind_from_irqhandler(vif->tx_irq, vif);
+ else {
+ unbind_from_irqhandler(vif->tx_irq, vif);
+ unbind_from_irqhandler(vif->rx_irq, vif);
+ }
+ /* vif->irq is valid, we had a module_get in
+ * xenvif_connect.
+ */
+ need_module_put = 1;
+ }
unregister_netdev(vif->dev);
xen_netbk_unmap_frontend_rings(vif);
free_netdev(vif->dev);
+
+ if (need_module_put)
+ module_put(THIS_MODULE);
}
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 37984e6..a0b50ad 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -47,6 +47,13 @@
#include <asm/xen/hypercall.h>
#include <asm/xen/page.h>
+/* Provide an option to disable split event channels at load time as
+ * event channels are limited resource. Split event channels are
+ * enabled by default.
+ */
+bool separate_tx_rx_irq = 1;
+module_param(separate_tx_rx_irq, bool, 0644);
+
/*
* This is the maximum slots a skb can have. If a guest sends a skb
* which exceeds this limit it is considered malicious.
@@ -662,7 +669,7 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk)
{
struct xenvif *vif = NULL, *tmp;
s8 status;
- u16 irq, flags;
+ u16 flags;
struct xen_netif_rx_response *resp;
struct sk_buff_head rxq;
struct sk_buff *skb;
@@ -771,20 +778,21 @@ static void xen_netbk_rx_action(struct xen_netbk *netbk)
sco->meta_slots_used);
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
- irq = vif->irq;
- if (ret && list_empty(&vif->notify_list))
- list_add_tail(&vif->notify_list, &notify);
xenvif_notify_tx_completion(vif);
- xenvif_put(vif);
+ if (ret && list_empty(&vif->notify_list))
+ list_add_tail(&vif->notify_list, &notify);
+ else
+ xenvif_put(vif);
npo.meta_cons += sco->meta_slots_used;
dev_kfree_skb(skb);
}
list_for_each_entry_safe(vif, tmp, &notify, notify_list) {
- notify_remote_via_irq(vif->irq);
+ notify_remote_via_irq(vif->rx_irq);
list_del_init(&vif->notify_list);
+ xenvif_put(vif);
}
/* More work to do? */
@@ -1762,7 +1770,7 @@ static void make_tx_response(struct xenvif *vif,
vif->tx.rsp_prod_pvt = ++i;
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->tx, notify);
if (notify)
- notify_remote_via_irq(vif->irq);
+ notify_remote_via_irq(vif->tx_irq);
}
static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
@@ -1939,10 +1947,6 @@ static int __init netback_init(void)
failed_init:
while (--group >= 0) {
struct xen_netbk *netbk = &xen_netbk[group];
- for (i = 0; i < MAX_PENDING_REQS; i++) {
- if (netbk->mmap_pages[i])
- __free_page(netbk->mmap_pages[i]);
- }
del_timer(&netbk->net_timer);
kthread_stop(netbk->task);
}
@@ -1953,5 +1957,25 @@ failed_init:
module_init(netback_init);
+static void __exit netback_fini(void)
+{
+ int i, j;
+
+ xenvif_xenbus_fini();
+
+ for (i = 0; i < xen_netbk_group_nr; i++) {
+ struct xen_netbk *netbk = &xen_netbk[i];
+ del_timer_sync(&netbk->net_timer);
+ kthread_stop(netbk->task);
+ for (j = 0; j < MAX_PENDING_REQS; j++) {
+ if (netbk->mmap_pages[i])
+ __free_page(netbk->mmap_pages[i]);
+ }
+ }
+
+ vfree(xen_netbk);
+}
+module_exit(netback_fini);
+
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("xen-backend:vif");
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 410018c..04bd860 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -122,6 +122,16 @@ static int netback_probe(struct xenbus_device *dev,
goto fail;
}
+ /*
+ * Split event channels support, this is optional so it is not
+ * put inside the above loop.
+ */
+ err = xenbus_printf(XBT_NIL, dev->nodename,
+ "feature-split-event-channels",
+ "%u", separate_tx_rx_irq);
+ if (err)
+ pr_debug("Error writing feature-split-event-channels");
+
err = xenbus_switch_state(dev, XenbusStateInitWait);
if (err)
goto fail;
@@ -393,21 +403,36 @@ static int connect_rings(struct backend_info *be)
struct xenvif *vif = be->vif;
struct xenbus_device *dev = be->dev;
unsigned long tx_ring_ref, rx_ring_ref;
- unsigned int evtchn, rx_copy;
+ unsigned int tx_evtchn, rx_evtchn, rx_copy;
int err;
int val;
err = xenbus_gather(XBT_NIL, dev->otherend,
"tx-ring-ref", "%lu", &tx_ring_ref,
- "rx-ring-ref", "%lu", &rx_ring_ref,
- "event-channel", "%u", &evtchn, NULL);
+ "rx-ring-ref", "%lu", &rx_ring_ref, NULL);
if (err) {
xenbus_dev_fatal(dev, err,
- "reading %s/ring-ref and event-channel",
+ "reading %s/ring-ref",
dev->otherend);
return err;
}
+ /* Try split event channels first, then single event channel. */
+ err = xenbus_gather(XBT_NIL, dev->otherend,
+ "event-channel-tx", "%u", &tx_evtchn,
+ "event-channel-rx", "%u", &rx_evtchn, NULL);
+ if (err < 0) {
+ err = xenbus_scanf(XBT_NIL, dev->otherend,
+ "event-channel", "%u", &tx_evtchn);
+ if (err < 0) {
+ xenbus_dev_fatal(dev, err,
+ "reading %s/event-channel(-tx/rx)",
+ dev->otherend);
+ return err;
+ }
+ rx_evtchn = tx_evtchn;
+ }
+
err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",
&rx_copy);
if (err == -ENOENT) {
@@ -454,11 +479,13 @@ static int connect_rings(struct backend_info *be)
vif->csum = !val;
/* Map the shared frame, irq etc. */
- err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref, evtchn);
+ err = xenvif_connect(vif, tx_ring_ref, rx_ring_ref,
+ tx_evtchn, rx_evtchn);
if (err) {
xenbus_dev_fatal(dev, err,
- "mapping shared-frames %lu/%lu port %u",
- tx_ring_ref, rx_ring_ref, evtchn);
+ "mapping shared-frames %lu/%lu port tx %u rx %u",
+ tx_ring_ref, rx_ring_ref,
+ tx_evtchn, rx_evtchn);
return err;
}
return 0;
@@ -485,3 +512,8 @@ int xenvif_xenbus_init(void)
{
return xenbus_register_backend(&netback_driver);
}
+
+void xenvif_xenbus_fini(void)
+{
+ return xenbus_unregister_driver(&netback_driver);
+}
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 1db10141..76a2236 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -85,7 +85,15 @@ struct netfront_info {
struct napi_struct napi;
- unsigned int evtchn;
+ /* Split event channels support, tx_* == rx_* when using
+ * single event channel.
+ */
+ unsigned int tx_evtchn, rx_evtchn;
+ unsigned int tx_irq, rx_irq;
+ /* Only used when split event channels support is enabled */
+ char tx_irq_name[IFNAMSIZ+4]; /* DEVNAME-tx */
+ char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */
+
struct xenbus_device *xbdev;
spinlock_t tx_lock;
@@ -330,7 +338,7 @@ no_skb:
push:
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
if (notify)
- notify_remote_via_irq(np->netdev->irq);
+ notify_remote_via_irq(np->rx_irq);
}
static int xennet_open(struct net_device *dev)
@@ -623,7 +631,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
if (notify)
- notify_remote_via_irq(np->netdev->irq);
+ notify_remote_via_irq(np->tx_irq);
u64_stats_update_begin(&stats->syncp);
stats->tx_bytes += skb->len;
@@ -850,7 +858,6 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np,
static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
{
struct iphdr *iph;
- unsigned char *th;
int err = -EPROTO;
int recalculate_partial_csum = 0;
@@ -875,27 +882,27 @@ static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
goto out;
iph = (void *)skb->data;
- th = skb->data + 4 * iph->ihl;
- if (th >= skb_tail_pointer(skb))
- goto out;
- skb->csum_start = th - skb->head;
switch (iph->protocol) {
case IPPROTO_TCP:
- skb->csum_offset = offsetof(struct tcphdr, check);
+ if (!skb_partial_csum_set(skb, 4 * iph->ihl,
+ offsetof(struct tcphdr, check)))
+ goto out;
if (recalculate_partial_csum) {
- struct tcphdr *tcph = (struct tcphdr *)th;
+ struct tcphdr *tcph = tcp_hdr(skb);
tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
skb->len - iph->ihl*4,
IPPROTO_TCP, 0);
}
break;
case IPPROTO_UDP:
- skb->csum_offset = offsetof(struct udphdr, check);
+ if (!skb_partial_csum_set(skb, 4 * iph->ihl,
+ offsetof(struct udphdr, check)))
+ goto out;
if (recalculate_partial_csum) {
- struct udphdr *udph = (struct udphdr *)th;
+ struct udphdr *udph = udp_hdr(skb);
udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
skb->len - iph->ihl*4,
IPPROTO_UDP, 0);
@@ -909,9 +916,6 @@ static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
goto out;
}
- if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
- goto out;
-
err = 0;
out:
@@ -1254,23 +1258,35 @@ static int xennet_set_features(struct net_device *dev,
return 0;
}
-static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = dev_id;
- struct netfront_info *np = netdev_priv(dev);
+ struct netfront_info *np = dev_id;
+ struct net_device *dev = np->netdev;
unsigned long flags;
spin_lock_irqsave(&np->tx_lock, flags);
+ xennet_tx_buf_gc(dev);
+ spin_unlock_irqrestore(&np->tx_lock, flags);
- if (likely(netif_carrier_ok(dev))) {
- xennet_tx_buf_gc(dev);
- /* Under tx_lock: protects access to rx shared-ring indexes. */
- if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id)
+{
+ struct netfront_info *np = dev_id;
+ struct net_device *dev = np->netdev;
+
+ if (likely(netif_carrier_ok(dev) &&
+ RING_HAS_UNCONSUMED_RESPONSES(&np->rx)))
napi_schedule(&np->napi);
- }
- spin_unlock_irqrestore(&np->tx_lock, flags);
+ return IRQ_HANDLED;
+}
+static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+{
+ xennet_tx_interrupt(irq, dev_id);
+ xennet_rx_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
@@ -1451,9 +1467,14 @@ static void xennet_disconnect_backend(struct netfront_info *info)
spin_unlock_irq(&info->tx_lock);
spin_unlock_bh(&info->rx_lock);
- if (info->netdev->irq)
- unbind_from_irqhandler(info->netdev->irq, info->netdev);
- info->evtchn = info->netdev->irq = 0;
+ if (info->tx_irq && (info->tx_irq == info->rx_irq))
+ unbind_from_irqhandler(info->tx_irq, info);
+ if (info->tx_irq && (info->tx_irq != info->rx_irq)) {
+ unbind_from_irqhandler(info->tx_irq, info);
+ unbind_from_irqhandler(info->rx_irq, info);
+ }
+ info->tx_evtchn = info->rx_evtchn = 0;
+ info->tx_irq = info->rx_irq = 0;
/* End access and free the pages */
xennet_end_access(info->tx_ring_ref, info->tx.sring);
@@ -1503,12 +1524,82 @@ static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
return 0;
}
+static int setup_netfront_single(struct netfront_info *info)
+{
+ int err;
+
+ err = xenbus_alloc_evtchn(info->xbdev, &info->tx_evtchn);
+ if (err < 0)
+ goto fail;
+
+ err = bind_evtchn_to_irqhandler(info->tx_evtchn,
+ xennet_interrupt,
+ 0, info->netdev->name, info);
+ if (err < 0)
+ goto bind_fail;
+ info->rx_evtchn = info->tx_evtchn;
+ info->rx_irq = info->tx_irq = err;
+
+ return 0;
+
+bind_fail:
+ xenbus_free_evtchn(info->xbdev, info->tx_evtchn);
+ info->tx_evtchn = 0;
+fail:
+ return err;
+}
+
+static int setup_netfront_split(struct netfront_info *info)
+{
+ int err;
+
+ err = xenbus_alloc_evtchn(info->xbdev, &info->tx_evtchn);
+ if (err < 0)
+ goto fail;
+ err = xenbus_alloc_evtchn(info->xbdev, &info->rx_evtchn);
+ if (err < 0)
+ goto alloc_rx_evtchn_fail;
+
+ snprintf(info->tx_irq_name, sizeof(info->tx_irq_name),
+ "%s-tx", info->netdev->name);
+ err = bind_evtchn_to_irqhandler(info->tx_evtchn,
+ xennet_tx_interrupt,
+ 0, info->tx_irq_name, info);
+ if (err < 0)
+ goto bind_tx_fail;
+ info->tx_irq = err;
+
+ snprintf(info->rx_irq_name, sizeof(info->rx_irq_name),
+ "%s-rx", info->netdev->name);
+ err = bind_evtchn_to_irqhandler(info->rx_evtchn,
+ xennet_rx_interrupt,
+ 0, info->rx_irq_name, info);
+ if (err < 0)
+ goto bind_rx_fail;
+ info->rx_irq = err;
+
+ return 0;
+
+bind_rx_fail:
+ unbind_from_irqhandler(info->tx_irq, info);
+ info->tx_irq = 0;
+bind_tx_fail:
+ xenbus_free_evtchn(info->xbdev, info->rx_evtchn);
+ info->rx_evtchn = 0;
+alloc_rx_evtchn_fail:
+ xenbus_free_evtchn(info->xbdev, info->tx_evtchn);
+ info->tx_evtchn = 0;
+fail:
+ return err;
+}
+
static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
{
struct xen_netif_tx_sring *txs;
struct xen_netif_rx_sring *rxs;
int err;
struct net_device *netdev = info->netdev;
+ unsigned int feature_split_evtchn;
info->tx_ring_ref = GRANT_INVALID_REF;
info->rx_ring_ref = GRANT_INVALID_REF;
@@ -1516,6 +1607,12 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
info->tx.sring = NULL;
netdev->irq = 0;
+ err = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
+ "feature-split-event-channels", "%u",
+ &feature_split_evtchn);
+ if (err < 0)
+ feature_split_evtchn = 0;
+
err = xen_net_read_mac(dev, netdev->dev_addr);
if (err) {
xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
@@ -1532,40 +1629,50 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
err = xenbus_grant_ring(dev, virt_to_mfn(txs));
- if (err < 0) {
- free_page((unsigned long)txs);
- goto fail;
- }
+ if (err < 0)
+ goto grant_tx_ring_fail;
info->tx_ring_ref = err;
rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
if (!rxs) {
err = -ENOMEM;
xenbus_dev_fatal(dev, err, "allocating rx ring page");
- goto fail;
+ goto alloc_rx_ring_fail;
}
SHARED_RING_INIT(rxs);
FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
- if (err < 0) {
- free_page((unsigned long)rxs);
- goto fail;
- }
+ if (err < 0)
+ goto grant_rx_ring_fail;
info->rx_ring_ref = err;
- err = xenbus_alloc_evtchn(dev, &info->evtchn);
+ if (feature_split_evtchn)
+ err = setup_netfront_split(info);
+ /* setup single event channel if
+ * a) feature-split-event-channels == 0
+ * b) feature-split-event-channels == 1 but failed to setup
+ */
+ if (!feature_split_evtchn || (feature_split_evtchn && err))
+ err = setup_netfront_single(info);
+
if (err)
- goto fail;
+ goto alloc_evtchn_fail;
- err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
- 0, netdev->name, netdev);
- if (err < 0)
- goto fail;
- netdev->irq = err;
return 0;
- fail:
+ /* If we fail to setup netfront, it is safe to just revoke access to
+ * granted pages because backend is not accessing it at this point.
+ */
+alloc_evtchn_fail:
+ gnttab_end_foreign_access_ref(info->rx_ring_ref, 0);
+grant_rx_ring_fail:
+ free_page((unsigned long)rxs);
+alloc_rx_ring_fail:
+ gnttab_end_foreign_access_ref(info->tx_ring_ref, 0);
+grant_tx_ring_fail:
+ free_page((unsigned long)txs);
+fail:
return err;
}
@@ -1601,11 +1708,27 @@ again:
message = "writing rx ring-ref";
goto abort_transaction;
}
- err = xenbus_printf(xbt, dev->nodename,
- "event-channel", "%u", info->evtchn);
- if (err) {
- message = "writing event-channel";
- goto abort_transaction;
+
+ if (info->tx_evtchn == info->rx_evtchn) {
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel", "%u", info->tx_evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+ } else {
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel-tx", "%u", info->tx_evtchn);
+ if (err) {
+ message = "writing event-channel-tx";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel-rx", "%u", info->rx_evtchn);
+ if (err) {
+ message = "writing event-channel-rx";
+ goto abort_transaction;
+ }
}
err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
@@ -1718,7 +1841,9 @@ static int xennet_connect(struct net_device *dev)
* packets.
*/
netif_carrier_on(np->netdev);
- notify_remote_via_irq(np->netdev->irq);
+ notify_remote_via_irq(np->tx_irq);
+ if (np->tx_irq != np->rx_irq)
+ notify_remote_via_irq(np->rx_irq);
xennet_tx_buf_gc(dev);
xennet_alloc_rx_buffers(dev);
diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c
index f802e7c..2dacd19 100644
--- a/drivers/ntb/ntb_hw.c
+++ b/drivers/ntb/ntb_hw.c
@@ -345,7 +345,7 @@ int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
*/
void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw)
{
- if (mw > NTB_NUM_MW)
+ if (mw >= NTB_NUM_MW)
return NULL;
return ndev->mw[mw].vbase;
@@ -362,7 +362,7 @@ void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw)
*/
resource_size_t ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
{
- if (mw > NTB_NUM_MW)
+ if (mw >= NTB_NUM_MW)
return 0;
return ndev->mw[mw].bar_sz;
@@ -380,7 +380,7 @@ resource_size_t ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
*/
void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
{
- if (mw > NTB_NUM_MW)
+ if (mw >= NTB_NUM_MW)
return;
dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr,
@@ -1027,8 +1027,8 @@ static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ndev->mw[i].vbase =
ioremap_wc(pci_resource_start(pdev, MW_TO_BAR(i)),
ndev->mw[i].bar_sz);
- dev_info(&pdev->dev, "MW %d size %d\n", i,
- (u32) pci_resource_len(pdev, MW_TO_BAR(i)));
+ dev_info(&pdev->dev, "MW %d size %llu\n", i,
+ pci_resource_len(pdev, MW_TO_BAR(i)));
if (!ndev->mw[i].vbase) {
dev_warn(&pdev->dev, "Cannot remap BAR %d\n",
MW_TO_BAR(i));
diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
index e0bdfd7..f8d7081 100644
--- a/drivers/ntb/ntb_transport.c
+++ b/drivers/ntb/ntb_transport.c
@@ -58,7 +58,7 @@
#include <linux/ntb.h>
#include "ntb_hw.h"
-#define NTB_TRANSPORT_VERSION 2
+#define NTB_TRANSPORT_VERSION 3
static unsigned int transport_mtu = 0x401E;
module_param(transport_mtu, uint, 0644);
@@ -173,10 +173,13 @@ struct ntb_payload_header {
enum {
VERSION = 0,
- MW0_SZ,
- MW1_SZ,
- NUM_QPS,
QP_LINKS,
+ NUM_QPS,
+ NUM_MWS,
+ MW0_SZ_HIGH,
+ MW0_SZ_LOW,
+ MW1_SZ_HIGH,
+ MW1_SZ_LOW,
MAX_SPAD,
};
@@ -297,7 +300,7 @@ int ntb_register_client_dev(char *device_name)
{
struct ntb_transport_client_dev *client_dev;
struct ntb_transport *nt;
- int rc;
+ int rc, i = 0;
if (list_empty(&ntb_transport_list))
return -ENODEV;
@@ -315,7 +318,7 @@ int ntb_register_client_dev(char *device_name)
dev = &client_dev->dev;
/* setup and register client devices */
- dev_set_name(dev, "%s", device_name);
+ dev_set_name(dev, "%s%d", device_name, i);
dev->bus = &ntb_bus_type;
dev->release = ntb_client_release;
dev->parent = &ntb_query_pdev(nt->ndev)->dev;
@@ -327,6 +330,7 @@ int ntb_register_client_dev(char *device_name)
}
list_add_tail(&client_dev->entry, &nt->client_devs);
+ i++;
}
return 0;
@@ -486,12 +490,13 @@ static void ntb_transport_setup_qp_mw(struct ntb_transport *nt,
(qp_num / NTB_NUM_MW * rx_size);
rx_size -= sizeof(struct ntb_rx_info);
- qp->rx_buff = qp->remote_rx_info + sizeof(struct ntb_rx_info);
- qp->rx_max_frame = min(transport_mtu, rx_size);
+ qp->rx_buff = qp->remote_rx_info + 1;
+ /* Due to housekeeping, there must be atleast 2 buffs */
+ qp->rx_max_frame = min(transport_mtu, rx_size / 2);
qp->rx_max_entry = rx_size / qp->rx_max_frame;
qp->rx_index = 0;
- qp->remote_rx_info->entry = qp->rx_max_entry;
+ qp->remote_rx_info->entry = qp->rx_max_entry - 1;
/* setup the hdr offsets with 0's */
for (i = 0; i < qp->rx_max_entry; i++) {
@@ -502,6 +507,19 @@ static void ntb_transport_setup_qp_mw(struct ntb_transport *nt,
qp->rx_pkts = 0;
qp->tx_pkts = 0;
+ qp->tx_index = 0;
+}
+
+static void ntb_free_mw(struct ntb_transport *nt, int num_mw)
+{
+ struct ntb_transport_mw *mw = &nt->mw[num_mw];
+ struct pci_dev *pdev = ntb_query_pdev(nt->ndev);
+
+ if (!mw->virt_addr)
+ return;
+
+ dma_free_coherent(&pdev->dev, mw->size, mw->virt_addr, mw->dma_addr);
+ mw->virt_addr = NULL;
}
static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size)
@@ -509,12 +527,20 @@ static int ntb_set_mw(struct ntb_transport *nt, int num_mw, unsigned int size)
struct ntb_transport_mw *mw = &nt->mw[num_mw];
struct pci_dev *pdev = ntb_query_pdev(nt->ndev);
+ /* No need to re-setup */
+ if (mw->size == ALIGN(size, 4096))
+ return 0;
+
+ if (mw->size != 0)
+ ntb_free_mw(nt, num_mw);
+
/* Alloc memory for receiving data. Must be 4k aligned */
mw->size = ALIGN(size, 4096);
mw->virt_addr = dma_alloc_coherent(&pdev->dev, mw->size, &mw->dma_addr,
GFP_KERNEL);
if (!mw->virt_addr) {
+ mw->size = 0;
dev_err(&pdev->dev, "Unable to allocate MW buffer of size %d\n",
(int) mw->size);
return -ENOMEM;
@@ -604,25 +630,31 @@ static void ntb_transport_link_work(struct work_struct *work)
u32 val;
int rc, i;
- /* send the local info */
- rc = ntb_write_remote_spad(ndev, VERSION, NTB_TRANSPORT_VERSION);
- if (rc) {
- dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
- 0, VERSION);
- goto out;
- }
+ /* send the local info, in the opposite order of the way we read it */
+ for (i = 0; i < NTB_NUM_MW; i++) {
+ rc = ntb_write_remote_spad(ndev, MW0_SZ_HIGH + (i * 2),
+ ntb_get_mw_size(ndev, i) >> 32);
+ if (rc) {
+ dev_err(&pdev->dev, "Error writing %u to remote spad %d\n",
+ (u32)(ntb_get_mw_size(ndev, i) >> 32),
+ MW0_SZ_HIGH + (i * 2));
+ goto out;
+ }
- rc = ntb_write_remote_spad(ndev, MW0_SZ, ntb_get_mw_size(ndev, 0));
- if (rc) {
- dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
- (u32) ntb_get_mw_size(ndev, 0), MW0_SZ);
- goto out;
+ rc = ntb_write_remote_spad(ndev, MW0_SZ_LOW + (i * 2),
+ (u32) ntb_get_mw_size(ndev, i));
+ if (rc) {
+ dev_err(&pdev->dev, "Error writing %u to remote spad %d\n",
+ (u32) ntb_get_mw_size(ndev, i),
+ MW0_SZ_LOW + (i * 2));
+ goto out;
+ }
}
- rc = ntb_write_remote_spad(ndev, MW1_SZ, ntb_get_mw_size(ndev, 1));
+ rc = ntb_write_remote_spad(ndev, NUM_MWS, NTB_NUM_MW);
if (rc) {
dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
- (u32) ntb_get_mw_size(ndev, 1), MW1_SZ);
+ NTB_NUM_MW, NUM_MWS);
goto out;
}
@@ -633,16 +665,10 @@ static void ntb_transport_link_work(struct work_struct *work)
goto out;
}
- rc = ntb_read_local_spad(nt->ndev, QP_LINKS, &val);
- if (rc) {
- dev_err(&pdev->dev, "Error reading spad %d\n", QP_LINKS);
- goto out;
- }
-
- rc = ntb_write_remote_spad(ndev, QP_LINKS, val);
+ rc = ntb_write_remote_spad(ndev, VERSION, NTB_TRANSPORT_VERSION);
if (rc) {
dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
- val, QP_LINKS);
+ NTB_TRANSPORT_VERSION, VERSION);
goto out;
}
@@ -667,33 +693,43 @@ static void ntb_transport_link_work(struct work_struct *work)
goto out;
dev_dbg(&pdev->dev, "Remote max number of qps = %d\n", val);
- rc = ntb_read_remote_spad(ndev, MW0_SZ, &val);
+ rc = ntb_read_remote_spad(ndev, NUM_MWS, &val);
if (rc) {
- dev_err(&pdev->dev, "Error reading remote spad %d\n", MW0_SZ);
+ dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_MWS);
goto out;
}
- if (!val)
+ if (val != NTB_NUM_MW)
goto out;
- dev_dbg(&pdev->dev, "Remote MW0 size = %d\n", val);
+ dev_dbg(&pdev->dev, "Remote number of mws = %d\n", val);
- rc = ntb_set_mw(nt, 0, val);
- if (rc)
- goto out;
+ for (i = 0; i < NTB_NUM_MW; i++) {
+ u64 val64;
- rc = ntb_read_remote_spad(ndev, MW1_SZ, &val);
- if (rc) {
- dev_err(&pdev->dev, "Error reading remote spad %d\n", MW1_SZ);
- goto out;
- }
+ rc = ntb_read_remote_spad(ndev, MW0_SZ_HIGH + (i * 2), &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading remote spad %d\n",
+ MW0_SZ_HIGH + (i * 2));
+ goto out1;
+ }
- if (!val)
- goto out;
- dev_dbg(&pdev->dev, "Remote MW1 size = %d\n", val);
+ val64 = (u64) val << 32;
- rc = ntb_set_mw(nt, 1, val);
- if (rc)
- goto out;
+ rc = ntb_read_remote_spad(ndev, MW0_SZ_LOW + (i * 2), &val);
+ if (rc) {
+ dev_err(&pdev->dev, "Error reading remote spad %d\n",
+ MW0_SZ_LOW + (i * 2));
+ goto out1;
+ }
+
+ val64 |= val;
+
+ dev_dbg(&pdev->dev, "Remote MW%d size = %llu\n", i, val64);
+
+ rc = ntb_set_mw(nt, i, val64);
+ if (rc)
+ goto out1;
+ }
nt->transport_link = NTB_LINK_UP;
@@ -708,6 +744,9 @@ static void ntb_transport_link_work(struct work_struct *work)
return;
+out1:
+ for (i = 0; i < NTB_NUM_MW; i++)
+ ntb_free_mw(nt, i);
out:
if (ntb_hw_link_status(ndev))
schedule_delayed_work(&nt->link_work,
@@ -780,10 +819,10 @@ static void ntb_transport_init_queue(struct ntb_transport *nt,
(qp_num / NTB_NUM_MW * tx_size);
tx_size -= sizeof(struct ntb_rx_info);
- qp->tx_mw = qp->rx_info + sizeof(struct ntb_rx_info);
- qp->tx_max_frame = min(transport_mtu, tx_size);
+ qp->tx_mw = qp->rx_info + 1;
+ /* Due to housekeeping, there must be atleast 2 buffs */
+ qp->tx_max_frame = min(transport_mtu, tx_size / 2);
qp->tx_max_entry = tx_size / qp->tx_max_frame;
- qp->tx_index = 0;
if (nt->debugfs_dir) {
char debugfs_name[4];
@@ -897,10 +936,7 @@ void ntb_transport_free(void *transport)
pdev = ntb_query_pdev(nt->ndev);
for (i = 0; i < NTB_NUM_MW; i++)
- if (nt->mw[i].virt_addr)
- dma_free_coherent(&pdev->dev, nt->mw[i].size,
- nt->mw[i].virt_addr,
- nt->mw[i].dma_addr);
+ ntb_free_mw(nt, i);
kfree(nt->qps);
ntb_unregister_transport(nt->ndev);
@@ -999,11 +1035,16 @@ out:
static void ntb_transport_rx(unsigned long data)
{
struct ntb_transport_qp *qp = (struct ntb_transport_qp *)data;
- int rc;
+ int rc, i;
- do {
+ /* Limit the number of packets processed in a single interrupt to
+ * provide fairness to others
+ */
+ for (i = 0; i < qp->rx_max_entry; i++) {
rc = ntb_process_rxc(qp);
- } while (!rc);
+ if (rc)
+ break;
+ }
}
static void ntb_transport_rxc_db(void *data, int db_num)
@@ -1210,12 +1251,14 @@ EXPORT_SYMBOL_GPL(ntb_transport_create_queue);
*/
void ntb_transport_free_queue(struct ntb_transport_qp *qp)
{
- struct pci_dev *pdev = ntb_query_pdev(qp->ndev);
+ struct pci_dev *pdev;
struct ntb_queue_entry *entry;
if (!qp)
return;
+ pdev = ntb_query_pdev(qp->ndev);
+
cancel_delayed_work_sync(&qp->link_work);
ntb_unregister_db_callback(qp->ndev, qp->qp_num);
@@ -1371,12 +1414,13 @@ EXPORT_SYMBOL_GPL(ntb_transport_link_up);
*/
void ntb_transport_link_down(struct ntb_transport_qp *qp)
{
- struct pci_dev *pdev = ntb_query_pdev(qp->ndev);
+ struct pci_dev *pdev;
int rc, val;
if (!qp)
return;
+ pdev = ntb_query_pdev(qp->ndev);
qp->client_ready = NTB_LINK_DOWN;
rc = ntb_read_local_spad(qp->ndev, QP_LINKS, &val);
@@ -1408,6 +1452,9 @@ EXPORT_SYMBOL_GPL(ntb_transport_link_down);
*/
bool ntb_transport_link_query(struct ntb_transport_qp *qp)
{
+ if (!qp)
+ return false;
+
return qp->qp_link == NTB_LINK_UP;
}
EXPORT_SYMBOL_GPL(ntb_transport_link_query);
@@ -1422,6 +1469,9 @@ EXPORT_SYMBOL_GPL(ntb_transport_link_query);
*/
unsigned char ntb_transport_qp_num(struct ntb_transport_qp *qp)
{
+ if (!qp)
+ return 0;
+
return qp->qp_num;
}
EXPORT_SYMBOL_GPL(ntb_transport_qp_num);
@@ -1436,6 +1486,9 @@ EXPORT_SYMBOL_GPL(ntb_transport_qp_num);
*/
unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
{
+ if (!qp)
+ return 0;
+
return qp->tx_max_frame - sizeof(struct ntb_payload_header);
}
EXPORT_SYMBOL_GPL(ntb_transport_max_size);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index c76d16c..a6f584a 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -192,14 +192,15 @@ EXPORT_SYMBOL(of_find_property);
struct device_node *of_find_all_nodes(struct device_node *prev)
{
struct device_node *np;
+ unsigned long flags;
- raw_spin_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
np = prev ? prev->allnext : of_allnodes;
for (; np != NULL; np = np->allnext)
if (of_node_get(np))
break;
of_node_put(prev);
- raw_spin_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_all_nodes);
@@ -421,8 +422,9 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
+ unsigned long flags;
- raw_spin_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling) {
if (!__of_device_is_available(next))
@@ -431,7 +433,7 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
break;
}
of_node_put(prev);
- raw_spin_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return next;
}
EXPORT_SYMBOL(of_get_next_available_child);
@@ -735,13 +737,14 @@ EXPORT_SYMBOL_GPL(of_modalias_node);
struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np;
+ unsigned long flags;
- raw_spin_lock(&devtree_lock);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
for (np = of_allnodes; np; np = np->allnext)
if (np->phandle == handle)
break;
of_node_get(np);
- raw_spin_unlock(&devtree_lock);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_by_phandle);
@@ -1208,11 +1211,11 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
out_args->args_count = count;
for (i = 0; i < count; i++)
out_args->args[i] = be32_to_cpup(list++);
+ } else {
+ of_node_put(node);
}
/* Found it! return success */
- if (node)
- of_node_put(node);
return 0;
}
diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c
index ffab033..ea174c8 100644
--- a/drivers/of/of_net.c
+++ b/drivers/of/of_net.c
@@ -22,6 +22,7 @@ static const char *phy_modes[] = {
[PHY_INTERFACE_MODE_GMII] = "gmii",
[PHY_INTERFACE_MODE_SGMII] = "sgmii",
[PHY_INTERFACE_MODE_TBI] = "tbi",
+ [PHY_INTERFACE_MODE_REVMII] = "rev-mii",
[PHY_INTERFACE_MODE_RMII] = "rmii",
[PHY_INTERFACE_MODE_RGMII] = "rgmii",
[PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id",
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 2ef7103..1f05913 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -668,7 +668,7 @@ lba_fixup_bus(struct pci_bus *bus)
BUG();
}
- if (ldev->hba.elmmio_space.start) {
+ if (ldev->hba.elmmio_space.flags) {
err = request_resource(&iomem_resource,
&(ldev->hba.elmmio_space));
if (err < 0) {
@@ -993,7 +993,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
case PAT_LMMIO:
/* used to fix up pre-initialized MEM BARs */
- if (!lba_dev->hba.lmmio_space.start) {
+ if (!lba_dev->hba.lmmio_space.flags) {
sprintf(lba_dev->hba.lmmio_name,
"PCI%02x LMMIO",
(int)lba_dev->hba.bus_num.start);
@@ -1001,7 +1001,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
io->start;
r = &lba_dev->hba.lmmio_space;
r->name = lba_dev->hba.lmmio_name;
- } else if (!lba_dev->hba.elmmio_space.start) {
+ } else if (!lba_dev->hba.elmmio_space.flags) {
sprintf(lba_dev->hba.elmmio_name,
"PCI%02x ELMMIO",
(int)lba_dev->hba.bus_num.start);
@@ -1096,6 +1096,7 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
r->name = "LBA PCI Busses";
r->start = lba_num & 0xff;
r->end = (lba_num>>8) & 0xff;
+ r->flags = IORESOURCE_BUS;
/* Set up local PCI Bus resources - we don't need them for
** Legacy boxes but it's nice to see in /proc/iomem.
@@ -1494,7 +1495,7 @@ lba_driver_probe(struct parisc_device *dev)
pci_add_resource_offset(&resources, &lba_dev->hba.io_space,
HBA_PORT_BASE(lba_dev->hba.hba_num));
- if (lba_dev->hba.elmmio_space.start)
+ if (lba_dev->hba.elmmio_space.flags)
pci_add_resource_offset(&resources, &lba_dev->hba.elmmio_space,
lba_dev->hba.lmmio_space_offset);
if (lba_dev->hba.lmmio_space.flags)
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index ac6e8e7..a042d06 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -494,15 +494,4 @@ static struct pci_driver superio_driver = {
.probe = superio_probe,
};
-static int __init superio_modinit(void)
-{
- return pci_register_driver(&superio_driver);
-}
-
-static void __exit superio_exit(void)
-{
- pci_unregister_driver(&superio_driver);
-}
-
-module_init(superio_modinit);
-module_exit(superio_exit);
+module_pci_driver(superio_driver);
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 24e12d4..a505760 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -71,7 +71,7 @@ config PARPORT_PC_FIFO
config PARPORT_PC_SUPERIO
bool "SuperIO chipset support"
- depends on PARPORT_PC
+ depends on PARPORT_PC && !PARISC
help
Saying Y here enables some probes for Super-IO chipsets in order to
find out things like base addresses, IRQ lines and DMA channels. It
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index a5251cb..6e3a60c 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -234,7 +234,7 @@ static int parport_PS2_supported(struct parport *pb)
struct parport *parport_gsc_probe_port(unsigned long base,
unsigned long base_hi, int irq,
- int dma, struct pci_dev *dev)
+ int dma, struct parisc_device *padev)
{
struct parport_gsc_private *priv;
struct parport_operations *ops;
@@ -258,7 +258,6 @@ struct parport *parport_gsc_probe_port(unsigned long base,
priv->ctr_writable = 0xff;
priv->dma_buf = 0;
priv->dma_handle = 0;
- priv->dev = dev;
p->base = base;
p->base_hi = base_hi;
p->irq = irq;
@@ -282,6 +281,7 @@ struct parport *parport_gsc_probe_port(unsigned long base,
return NULL;
}
+ p->dev = &padev->dev;
p->base_hi = base_hi;
p->modes = tmp.modes;
p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
@@ -373,7 +373,7 @@ static int parport_init_chip(struct parisc_device *dev)
}
p = parport_gsc_probe_port(port, 0, dev->irq,
- /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, NULL);
+ /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, dev);
if (p)
parport_count++;
dev_set_drvdata(&dev->dev, p);
diff --git a/drivers/parport/parport_gsc.h b/drivers/parport/parport_gsc.h
index fc9c37c..8122147 100644
--- a/drivers/parport/parport_gsc.h
+++ b/drivers/parport/parport_gsc.h
@@ -217,6 +217,6 @@ extern void parport_gsc_dec_use_count(void);
extern struct parport *parport_gsc_probe_port(unsigned long base,
unsigned long base_hi,
int irq, int dma,
- struct pci_dev *dev);
+ struct parisc_device *padev);
#endif /* __DRIVERS_PARPORT_PARPORT_GSC_H */
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 96fed19..716aa93 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -950,6 +950,20 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK ;
}
+void acpiphp_check_host_bridge(acpi_handle handle)
+{
+ struct acpiphp_bridge *bridge;
+
+ bridge = acpiphp_handle_to_bridge(handle);
+ if (bridge) {
+ acpiphp_check_bridge(bridge);
+ put_bridge(bridge);
+ }
+
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL);
+}
+
static void _handle_hotplug_event_bridge(struct work_struct *work)
{
struct acpiphp_bridge *bridge;
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 8ec8b4f..0f4554e 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -580,6 +580,7 @@ struct aer_recover_entry
u8 devfn;
u16 domain;
int severity;
+ struct aer_capability_regs *regs;
};
static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry,
@@ -593,7 +594,7 @@ static DEFINE_SPINLOCK(aer_recover_ring_lock);
static DECLARE_WORK(aer_recover_work, aer_recover_work_func);
void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
- int severity)
+ int severity, struct aer_capability_regs *aer_regs)
{
unsigned long flags;
struct aer_recover_entry entry = {
@@ -601,6 +602,7 @@ void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn,
.devfn = devfn,
.domain = domain,
.severity = severity,
+ .regs = aer_regs,
};
spin_lock_irqsave(&aer_recover_ring_lock, flags);
@@ -627,6 +629,7 @@ static void aer_recover_work_func(struct work_struct *work)
PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn));
continue;
}
+ cper_print_aer(pdev, entry.severity, entry.regs);
do_recovery(pdev, entry.severity);
pci_dev_put(pdev);
}
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
index 5ab1425..2c7c9f5 100644
--- a/drivers/pci/pcie/aer/aerdrv_errprint.c
+++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
@@ -220,7 +220,7 @@ int cper_severity_to_aer(int cper_severity)
}
EXPORT_SYMBOL_GPL(cper_severity_to_aer);
-void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity,
+void cper_print_aer(struct pci_dev *dev, int cper_severity,
struct aer_capability_regs *aer)
{
int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0;
@@ -244,7 +244,7 @@ void cper_print_aer(const char *prefix, struct pci_dev *dev, int cper_severity,
agent = AER_GET_AGENT(aer_severity, status);
dev_err(&dev->dev, "aer_status: 0x%08x, aer_mask: 0x%08x\n",
status, mask);
- cper_print_bits(prefix, status, status_strs, status_strs_size);
+ cper_print_bits("", status, status_strs, status_strs_size);
dev_err(&dev->dev, "aer_layer=%s, aer_agent=%s\n",
aer_error_layer[layer], aer_agent_string[agent]);
if (aer_severity != AER_CORRECTABLE)
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index c67c37e..694c3ac 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -610,7 +610,7 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d)
bool found = false;
unsigned long config;
- mutex_lock(&pctldev->mutex);
+ mutex_lock(&pinctrl_maps_mutex);
/* Parse the pinctrl map and look for the elected pin/state */
for_each_maps(maps_node, i, map) {
@@ -659,7 +659,7 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d)
confops->pin_config_config_dbg_show(pctldev, s, config);
exit:
- mutex_unlock(&pctldev->mutex);
+ mutex_unlock(&pinctrl_maps_mutex);
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c
index aa17f75..6d45327 100644
--- a/drivers/pinctrl/pinctrl-abx500.c
+++ b/drivers/pinctrl/pinctrl-abx500.c
@@ -851,23 +851,12 @@ static int abx500_gpio_probe(struct platform_device *pdev)
if (abx500_pdata)
pdata = abx500_pdata->gpio;
- if (!pdata) {
- if (np) {
- const struct of_device_id *match;
- match = of_match_device(abx500_gpio_match, &pdev->dev);
- if (!match)
- return -ENODEV;
- id = (unsigned long)match->data;
- } else {
- dev_err(&pdev->dev, "gpio dt and platform data missing\n");
- return -ENODEV;
- }
+ if (!(pdata || np)) {
+ dev_err(&pdev->dev, "gpio dt and platform data missing\n");
+ return -ENODEV;
}
- if (platid)
- id = platid->driver_data;
-
pct = devm_kzalloc(&pdev->dev, sizeof(struct abx500_pinctrl),
GFP_KERNEL);
if (pct == NULL) {
@@ -882,6 +871,16 @@ static int abx500_gpio_probe(struct platform_device *pdev)
pct->chip.dev = &pdev->dev;
pct->chip.base = (np) ? -1 : pdata->gpio_base;
+ if (platid)
+ id = platid->driver_data;
+ else if (np) {
+ const struct of_device_id *match;
+
+ match = of_match_device(abx500_gpio_match, &pdev->dev);
+ if (match)
+ id = (unsigned long)match->data;
+ }
+
/* initialize the lock */
mutex_init(&pct->lock);
@@ -900,8 +899,7 @@ static int abx500_gpio_probe(struct platform_device *pdev)
abx500_pinctrl_ab8505_init(&pct->soc);
break;
default:
- dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n",
- (int) platid->driver_data);
+ dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n", id);
mutex_destroy(&pct->lock);
return -EINVAL;
}
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index edde3ac..d6b4174 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -713,11 +713,6 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
gpio->dev = &pdev->dev;
memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!memres) {
- dev_err(gpio->dev, "could not get GPIO memory resource\n");
- return -ENODEV;
- }
-
gpio->base = devm_ioremap_resource(&pdev->dev, memres);
if (IS_ERR(gpio->base))
return PTR_ERR(gpio->base);
@@ -835,7 +830,8 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
return 0;
err_no_range:
- err = gpiochip_remove(&gpio->chip);
+ if (gpiochip_remove(&gpio->chip))
+ dev_err(&pdev->dev, "failed to remove gpio chip\n");
err_no_chip:
err_no_domain:
err_no_port:
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index ac74281..2d76f66 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -196,6 +196,12 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
return IRQ_HANDLED;
}
+struct exynos_eint_gpio_save {
+ u32 eint_con;
+ u32 eint_fltcon0;
+ u32 eint_fltcon1;
+};
+
/*
* exynos_eint_gpio_init() - setup handling of external gpio interrupts.
* @d: driver data of samsung pinctrl driver.
@@ -204,8 +210,8 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
{
struct samsung_pin_bank *bank;
struct device *dev = d->dev;
- unsigned int ret;
- unsigned int i;
+ int ret;
+ int i;
if (!d->irq) {
dev_err(dev, "irq number not available\n");
@@ -227,11 +233,29 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
bank->nr_pins, &exynos_gpio_irqd_ops, bank);
if (!bank->irq_domain) {
dev_err(dev, "gpio irq domain add failed\n");
- return -ENXIO;
+ ret = -ENXIO;
+ goto err_domains;
+ }
+
+ bank->soc_priv = devm_kzalloc(d->dev,
+ sizeof(struct exynos_eint_gpio_save), GFP_KERNEL);
+ if (!bank->soc_priv) {
+ irq_domain_remove(bank->irq_domain);
+ ret = -ENOMEM;
+ goto err_domains;
}
}
return 0;
+
+err_domains:
+ for (--i, --bank; i >= 0; --i, --bank) {
+ if (bank->eint_type != EINT_TYPE_GPIO)
+ continue;
+ irq_domain_remove(bank->irq_domain);
+ }
+
+ return ret;
}
static void exynos_wkup_irq_unmask(struct irq_data *irqd)
@@ -326,6 +350,28 @@ static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
return 0;
}
+static u32 exynos_eint_wake_mask = 0xffffffff;
+
+u32 exynos_get_eint_wake_mask(void)
+{
+ return exynos_eint_wake_mask;
+}
+
+static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
+
+ pr_info("wake %s for irq %d\n", on ? "enabled" : "disabled", irqd->irq);
+
+ if (!on)
+ exynos_eint_wake_mask |= bit;
+ else
+ exynos_eint_wake_mask &= ~bit;
+
+ return 0;
+}
+
/*
* irq_chip for wakeup interrupts
*/
@@ -335,6 +381,7 @@ static struct irq_chip exynos_wkup_irq_chip = {
.irq_mask = exynos_wkup_irq_mask,
.irq_ack = exynos_wkup_irq_ack,
.irq_set_type = exynos_wkup_irq_set_type,
+ .irq_set_wake = exynos_wkup_irq_set_wake,
};
/* interrupt handler for wakeup interrupts 0..15 */
@@ -505,6 +552,72 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
return 0;
}
+static void exynos_pinctrl_suspend_bank(
+ struct samsung_pinctrl_drv_data *drvdata,
+ struct samsung_pin_bank *bank)
+{
+ struct exynos_eint_gpio_save *save = bank->soc_priv;
+ void __iomem *regs = drvdata->virt_base;
+
+ save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ + bank->eint_offset);
+ save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ + 2 * bank->eint_offset);
+ save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ + 2 * bank->eint_offset + 4);
+
+ pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
+ pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
+ pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
+}
+
+static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
+{
+ struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+ struct samsung_pin_bank *bank = ctrl->pin_banks;
+ int i;
+
+ for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
+ if (bank->eint_type == EINT_TYPE_GPIO)
+ exynos_pinctrl_suspend_bank(drvdata, bank);
+}
+
+static void exynos_pinctrl_resume_bank(
+ struct samsung_pinctrl_drv_data *drvdata,
+ struct samsung_pin_bank *bank)
+{
+ struct exynos_eint_gpio_save *save = bank->soc_priv;
+ void __iomem *regs = drvdata->virt_base;
+
+ pr_debug("%s: con %#010x => %#010x\n", bank->name,
+ readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ + bank->eint_offset), save->eint_con);
+ pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name,
+ readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ + 2 * bank->eint_offset), save->eint_fltcon0);
+ pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name,
+ readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ + 2 * bank->eint_offset + 4), save->eint_fltcon1);
+
+ writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET
+ + bank->eint_offset);
+ writel(save->eint_fltcon0, regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ + 2 * bank->eint_offset);
+ writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ + 2 * bank->eint_offset + 4);
+}
+
+static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
+{
+ struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+ struct samsung_pin_bank *bank = ctrl->pin_banks;
+ int i;
+
+ for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
+ if (bank->eint_type == EINT_TYPE_GPIO)
+ exynos_pinctrl_resume_bank(drvdata, bank);
+}
+
/* pin banks of exynos4210 pin-controller 0 */
static struct samsung_pin_bank exynos4210_pin_banks0[] = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -568,6 +681,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos4210-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
@@ -582,6 +697,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos4210-gpio-ctrl1",
}, {
/* pin-controller instance 2 data */
@@ -663,6 +780,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos4x12-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
@@ -677,6 +796,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos4x12-gpio-ctrl1",
}, {
/* pin-controller instance 2 data */
@@ -687,6 +808,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos4x12-gpio-ctrl2",
}, {
/* pin-controller instance 3 data */
@@ -697,6 +820,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos4x12-gpio-ctrl3",
},
};
@@ -775,6 +900,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos5250-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
@@ -785,6 +912,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos5250-gpio-ctrl1",
}, {
/* pin-controller instance 2 data */
@@ -795,6 +924,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos5250-gpio-ctrl2",
}, {
/* pin-controller instance 3 data */
@@ -805,6 +936,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
.label = "exynos5250-gpio-ctrl3",
},
};
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h
index 9b1f77a..3c91c35 100644
--- a/drivers/pinctrl/pinctrl-exynos.h
+++ b/drivers/pinctrl/pinctrl-exynos.h
@@ -19,6 +19,7 @@
/* External GPIO and wakeup interrupt related definitions */
#define EXYNOS_GPIO_ECON_OFFSET 0x700
+#define EXYNOS_GPIO_EFLTCON_OFFSET 0x800
#define EXYNOS_GPIO_EMASK_OFFSET 0x900
#define EXYNOS_GPIO_EPEND_OFFSET 0xA00
#define EXYNOS_WKUP_ECON_OFFSET 0xE00
diff --git a/drivers/pinctrl/pinctrl-exynos5440.c b/drivers/pinctrl/pinctrl-exynos5440.c
index 6038503..32a48f4 100644
--- a/drivers/pinctrl/pinctrl-exynos5440.c
+++ b/drivers/pinctrl/pinctrl-exynos5440.c
@@ -1000,11 +1000,6 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "cannot find IO resource\n");
- return -ENOENT;
- }
-
priv->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->reg_base))
return PTR_ERR(priv->reg_base);
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c
index 615c500..d22ca25 100644
--- a/drivers/pinctrl/pinctrl-lantiq.c
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -52,7 +52,8 @@ static void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
int i;
for (i = 0; i < num_maps; i++)
- if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
+ if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN ||
+ map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
kfree(map[i].data.configs.configs);
kfree(map);
}
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 9763668..63ac22e 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -28,6 +28,7 @@
#include <linux/gpio.h>
#include <linux/irqdomain.h>
#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
#include "core.h"
#include "pinctrl-samsung.h"
@@ -48,6 +49,9 @@ static struct pin_config {
{ "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN },
};
+/* Global list of devices (struct samsung_pinctrl_drv_data) */
+LIST_HEAD(drvdata_list);
+
static unsigned int pin_base;
static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
@@ -932,11 +936,6 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
drvdata->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "cannot find IO resource\n");
- return -ENOENT;
- }
-
drvdata->virt_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(drvdata->virt_base))
return PTR_ERR(drvdata->virt_base);
@@ -961,9 +960,151 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
ctrl->eint_wkup_init(drvdata);
platform_set_drvdata(pdev, drvdata);
+
+ /* Add to the global list */
+ list_add_tail(&drvdata->node, &drvdata_list);
+
return 0;
}
+#ifdef CONFIG_PM
+
+/**
+ * samsung_pinctrl_suspend_dev - save pinctrl state for suspend for a device
+ *
+ * Save data for all banks handled by this device.
+ */
+static void samsung_pinctrl_suspend_dev(
+ struct samsung_pinctrl_drv_data *drvdata)
+{
+ struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+ void __iomem *virt_base = drvdata->virt_base;
+ int i;
+
+ for (i = 0; i < ctrl->nr_banks; i++) {
+ struct samsung_pin_bank *bank = &ctrl->pin_banks[i];
+ void __iomem *reg = virt_base + bank->pctl_offset;
+
+ u8 *offs = bank->type->reg_offset;
+ u8 *widths = bank->type->fld_width;
+ enum pincfg_type type;
+
+ /* Registers without a powerdown config aren't lost */
+ if (!widths[PINCFG_TYPE_CON_PDN])
+ continue;
+
+ for (type = 0; type < PINCFG_TYPE_NUM; type++)
+ if (widths[type])
+ bank->pm_save[type] = readl(reg + offs[type]);
+
+ if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
+ /* Some banks have two config registers */
+ bank->pm_save[PINCFG_TYPE_NUM] =
+ readl(reg + offs[PINCFG_TYPE_FUNC] + 4);
+ pr_debug("Save %s @ %p (con %#010x %08x)\n",
+ bank->name, reg,
+ bank->pm_save[PINCFG_TYPE_FUNC],
+ bank->pm_save[PINCFG_TYPE_NUM]);
+ } else {
+ pr_debug("Save %s @ %p (con %#010x)\n", bank->name,
+ reg, bank->pm_save[PINCFG_TYPE_FUNC]);
+ }
+ }
+
+ if (ctrl->suspend)
+ ctrl->suspend(drvdata);
+}
+
+/**
+ * samsung_pinctrl_resume_dev - restore pinctrl state from suspend for a device
+ *
+ * Restore one of the banks that was saved during suspend.
+ *
+ * We don't bother doing anything complicated to avoid glitching lines since
+ * we're called before pad retention is turned off.
+ */
+static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata)
+{
+ struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
+ void __iomem *virt_base = drvdata->virt_base;
+ int i;
+
+ if (ctrl->resume)
+ ctrl->resume(drvdata);
+
+ for (i = 0; i < ctrl->nr_banks; i++) {
+ struct samsung_pin_bank *bank = &ctrl->pin_banks[i];
+ void __iomem *reg = virt_base + bank->pctl_offset;
+
+ u8 *offs = bank->type->reg_offset;
+ u8 *widths = bank->type->fld_width;
+ enum pincfg_type type;
+
+ /* Registers without a powerdown config aren't lost */
+ if (!widths[PINCFG_TYPE_CON_PDN])
+ continue;
+
+ if (widths[PINCFG_TYPE_FUNC] * bank->nr_pins > 32) {
+ /* Some banks have two config registers */
+ pr_debug("%s @ %p (con %#010x %08x => %#010x %08x)\n",
+ bank->name, reg,
+ readl(reg + offs[PINCFG_TYPE_FUNC]),
+ readl(reg + offs[PINCFG_TYPE_FUNC] + 4),
+ bank->pm_save[PINCFG_TYPE_FUNC],
+ bank->pm_save[PINCFG_TYPE_NUM]);
+ writel(bank->pm_save[PINCFG_TYPE_NUM],
+ reg + offs[PINCFG_TYPE_FUNC] + 4);
+ } else {
+ pr_debug("%s @ %p (con %#010x => %#010x)\n", bank->name,
+ reg, readl(reg + offs[PINCFG_TYPE_FUNC]),
+ bank->pm_save[PINCFG_TYPE_FUNC]);
+ }
+ for (type = 0; type < PINCFG_TYPE_NUM; type++)
+ if (widths[type])
+ writel(bank->pm_save[type], reg + offs[type]);
+ }
+}
+
+/**
+ * samsung_pinctrl_suspend - save pinctrl state for suspend
+ *
+ * Save data for all banks across all devices.
+ */
+static int samsung_pinctrl_suspend(void)
+{
+ struct samsung_pinctrl_drv_data *drvdata;
+
+ list_for_each_entry(drvdata, &drvdata_list, node) {
+ samsung_pinctrl_suspend_dev(drvdata);
+ }
+
+ return 0;
+}
+
+/**
+ * samsung_pinctrl_resume - restore pinctrl state for suspend
+ *
+ * Restore data for all banks across all devices.
+ */
+static void samsung_pinctrl_resume(void)
+{
+ struct samsung_pinctrl_drv_data *drvdata;
+
+ list_for_each_entry_reverse(drvdata, &drvdata_list, node) {
+ samsung_pinctrl_resume_dev(drvdata);
+ }
+}
+
+#else
+#define samsung_pinctrl_suspend NULL
+#define samsung_pinctrl_resume NULL
+#endif
+
+static struct syscore_ops samsung_pinctrl_syscore_ops = {
+ .suspend = samsung_pinctrl_suspend,
+ .resume = samsung_pinctrl_resume,
+};
+
static const struct of_device_id samsung_pinctrl_dt_match[] = {
#ifdef CONFIG_PINCTRL_EXYNOS
{ .compatible = "samsung,exynos4210-pinctrl",
@@ -992,6 +1133,14 @@ static struct platform_driver samsung_pinctrl_driver = {
static int __init samsung_pinctrl_drv_register(void)
{
+ /*
+ * Register syscore ops for save/restore of registers across suspend.
+ * It's important to ensure that this driver is running at an earlier
+ * initcall level than any arch-specific init calls that install syscore
+ * ops that turn off pad retention (like exynos_pm_resume).
+ */
+ register_syscore_ops(&samsung_pinctrl_syscore_ops);
+
return platform_driver_register(&samsung_pinctrl_driver);
}
postcore_initcall(samsung_pinctrl_drv_register);
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index 7c7f9eb..26d3519 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -127,6 +127,7 @@ struct samsung_pin_bank_type {
* @gpio_chip: GPIO chip of the bank.
* @grange: linux gpio pin range supported by this bank.
* @slock: spinlock protecting bank registers
+ * @pm_save: saved register values during suspend
*/
struct samsung_pin_bank {
struct samsung_pin_bank_type *type;
@@ -138,12 +139,15 @@ struct samsung_pin_bank {
u32 eint_mask;
u32 eint_offset;
char *name;
+ void *soc_priv;
struct device_node *of_node;
struct samsung_pinctrl_drv_data *drvdata;
struct irq_domain *irq_domain;
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range grange;
spinlock_t slock;
+
+ u32 pm_save[PINCFG_TYPE_NUM + 1]; /* +1 to handle double CON registers*/
};
/**
@@ -184,11 +188,15 @@ struct samsung_pin_ctrl {
int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *);
+ void (*suspend)(struct samsung_pinctrl_drv_data *);
+ void (*resume)(struct samsung_pinctrl_drv_data *);
+
char *label;
};
/**
* struct samsung_pinctrl_drv_data: wrapper for holding driver data together.
+ * @node: global list node
* @virt_base: register base address of the controller.
* @dev: device instance representing the controller.
* @irq: interrpt number used by the controller to notify gpio interrupts.
@@ -201,6 +209,7 @@ struct samsung_pin_ctrl {
* @nr_function: number of such pin functions.
*/
struct samsung_pinctrl_drv_data {
+ struct list_head node;
void __iomem *virt_base;
struct device *dev;
int irq;
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 5f2d2bf..b9fa046 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1166,7 +1166,8 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
(*map)->data.mux.function = np->name;
if (pcs->is_pinconf) {
- if (pcs_parse_pinconf(pcs, np, function, map))
+ res = pcs_parse_pinconf(pcs, np, function, map);
+ if (res)
goto free_pingroups;
*num_maps = 2;
} else {
diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
index c52fc2c..b7d8c89 100644
--- a/drivers/pinctrl/pinctrl-sunxi.c
+++ b/drivers/pinctrl/pinctrl-sunxi.c
@@ -1990,8 +1990,10 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
}
clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk))
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
goto gpiochip_error;
+ }
clk_prepare_enable(clk);
@@ -2000,7 +2002,8 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev)
return 0;
gpiochip_error:
- ret = gpiochip_remove(pctl->chip);
+ if (gpiochip_remove(pctl->chip))
+ dev_err(&pdev->dev, "failed to remove gpio chip\n");
pinctrl_error:
pinctrl_unregister(pctl->pctl_dev);
return ret;
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index f2977cf..e92132c 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -716,10 +716,6 @@ static int pinmux_xway_probe(struct platform_device *pdev)
/* get and remap our register range */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get resource\n");
- return -ENOENT;
- }
xway_info.membase[0] = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xway_info.membase[0]))
return PTR_ERR(xway_info.membase[0]);
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
index 791a671..8cd90e7 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
@@ -2357,27 +2357,48 @@ static const unsigned int sdhi3_wp_mux[] = {
};
/* - USB0 ------------------------------------------------------------------- */
static const unsigned int usb0_pins[] = {
- /* OVC */
- 150, 154,
+ /* PENC */
+ 154,
};
static const unsigned int usb0_mux[] = {
- USB_OVC0_MARK, USB_PENC0_MARK,
+ USB_PENC0_MARK,
+};
+static const unsigned int usb0_ovc_pins[] = {
+ /* USB_OVC */
+ 150
+};
+static const unsigned int usb0_ovc_mux[] = {
+ USB_OVC0_MARK,
};
/* - USB1 ------------------------------------------------------------------- */
static const unsigned int usb1_pins[] = {
- /* OVC */
- 152, 155,
+ /* PENC */
+ 155,
};
static const unsigned int usb1_mux[] = {
- USB_OVC1_MARK, USB_PENC1_MARK,
+ USB_PENC1_MARK,
+};
+static const unsigned int usb1_ovc_pins[] = {
+ /* USB_OVC */
+ 152,
+};
+static const unsigned int usb1_ovc_mux[] = {
+ USB_OVC1_MARK,
};
/* - USB2 ------------------------------------------------------------------- */
static const unsigned int usb2_pins[] = {
- /* OVC, PENC */
- 125, 156,
+ /* PENC */
+ 156,
};
static const unsigned int usb2_mux[] = {
- USB_OVC2_MARK, USB_PENC2_MARK,
+ USB_PENC2_MARK,
+};
+static const unsigned int usb2_ovc_pins[] = {
+ /* USB_OVC */
+ 125,
+};
+static const unsigned int usb2_ovc_mux[] = {
+ USB_OVC2_MARK,
};
static const struct sh_pfc_pin_group pinmux_groups[] = {
@@ -2501,8 +2522,11 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(sdhi3_cd),
SH_PFC_PIN_GROUP(sdhi3_wp),
SH_PFC_PIN_GROUP(usb0),
+ SH_PFC_PIN_GROUP(usb0_ovc),
SH_PFC_PIN_GROUP(usb1),
+ SH_PFC_PIN_GROUP(usb1_ovc),
SH_PFC_PIN_GROUP(usb2),
+ SH_PFC_PIN_GROUP(usb2_ovc),
};
static const char * const du0_groups[] = {
@@ -2683,14 +2707,17 @@ static const char * const sdhi3_groups[] = {
static const char * const usb0_groups[] = {
"usb0",
+ "usb0_ovc",
};
static const char * const usb1_groups[] = {
"usb1",
+ "usb1_ovc",
};
static const char * const usb2_groups[] = {
"usb2",
+ "usb2_ovc",
};
static const struct sh_pfc_function pinmux_functions[] = {
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8750.c b/drivers/pinctrl/vt8500/pinctrl-wm8750.c
index b964cc5..de43262 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8750.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8750.c
@@ -53,7 +53,7 @@ static const struct wmt_pinctrl_bank_registers wm8750_banks[] = {
#define WMT_PIN_EXTGPIO6 WMT_PIN(0, 6)
#define WMT_PIN_EXTGPIO7 WMT_PIN(0, 7)
#define WMT_PIN_WAKEUP0 WMT_PIN(0, 16)
-#define WMT_PIN_WAKEUP1 WMT_PIN(0, 16)
+#define WMT_PIN_WAKEUP1 WMT_PIN(0, 17)
#define WMT_PIN_SD0CD WMT_PIN(0, 28)
#define WMT_PIN_VDOUT0 WMT_PIN(1, 0)
#define WMT_PIN_VDOUT1 WMT_PIN(1, 1)
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index ab63104..70d986e 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -609,8 +609,7 @@ int wmt_pinctrl_probe(struct platform_device *pdev,
return 0;
fail_range:
- err = gpiochip_remove(&data->gpio_chip);
- if (err)
+ if (gpiochip_remove(&data->gpio_chip))
dev_err(&pdev->dev, "failed to remove gpio chip\n");
fail_gpio:
pinctrl_unregister(data->pctl_dev);
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 8df0c5a..d111c86 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -703,7 +703,7 @@ static int hp_wmi_rfkill_setup(struct platform_device *device)
}
rfkill_init_sw_state(gps_rfkill,
hp_wmi_get_sw_state(HPWMI_GPS));
- rfkill_set_hw_state(bluetooth_rfkill,
+ rfkill_set_hw_state(gps_rfkill,
hp_wmi_get_hw_state(HPWMI_GPS));
err = rfkill_register(gps_rfkill);
if (err)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 0d0b5d7..7b8979c 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -152,6 +152,7 @@ config BATTERY_SBS
config BATTERY_BQ27x00
tristate "BQ27x00 battery driver"
+ depends on I2C || I2C=n
help
Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips.
@@ -284,6 +285,7 @@ config CHARGER_LP8788
tristate "TI LP8788 charger driver"
depends on MFD_LP8788
depends on LP8788_ADC
+ depends on IIO
help
Say Y to enable support for the LP8788 linear charger.
diff --git a/drivers/power/pm2301_charger.c b/drivers/power/pm2301_charger.c
index a441751..fef56e2 100644
--- a/drivers/power/pm2301_charger.c
+++ b/drivers/power/pm2301_charger.c
@@ -1269,5 +1269,5 @@ module_exit(pm2xxx_charger_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rajkumar kasirajan, Olivier Launay");
-MODULE_ALIAS("platform:pm2xxx-charger");
+MODULE_ALIAS("i2c:pm2xxx-charger");
MODULE_DESCRIPTION("PM2xxx charger management driver");
diff --git a/drivers/power/wm831x_backup.c b/drivers/power/wm831x_backup.c
index 58cbb00..56fb509 100644
--- a/drivers/power/wm831x_backup.c
+++ b/drivers/power/wm831x_backup.c
@@ -207,7 +207,6 @@ static int wm831x_backup_remove(struct platform_device *pdev)
struct wm831x_backup *devdata = platform_get_drvdata(pdev);
power_supply_unregister(&devdata->backup);
- kfree(devdata->backup.name);
return 0;
}
diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c
index bea9451..71a2559 100644
--- a/drivers/ptp/ptp_pch.c
+++ b/drivers/ptp/ptp_pch.c
@@ -628,9 +628,10 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
chip->caps = ptp_pch_caps;
chip->ptp_clock = ptp_clock_register(&chip->caps, &pdev->dev);
-
- if (IS_ERR(chip->ptp_clock))
- return PTR_ERR(chip->ptp_clock);
+ if (IS_ERR(chip->ptp_clock)) {
+ ret = PTR_ERR(chip->ptp_clock);
+ goto err_ptp_clock_reg;
+ }
spin_lock_init(&chip->register_lock);
@@ -669,6 +670,7 @@ pch_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_req_irq:
ptp_clock_unregister(chip->ptp_clock);
+err_ptp_clock_reg:
iounmap(chip->regs);
chip->regs = NULL;
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index ec28798..c938bae 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -265,11 +265,6 @@ static int imx_pwm_probe(struct platform_device *pdev)
imx->chip.npwm = 1;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- return -ENODEV;
- }
-
imx->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(imx->mmio_base))
return PTR_ERR(imx->mmio_base);
diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c
index d1eb499..ed6007b 100644
--- a/drivers/pwm/pwm-puv3.c
+++ b/drivers/pwm/pwm-puv3.c
@@ -117,11 +117,6 @@ static int pwm_probe(struct platform_device *pdev)
return PTR_ERR(puv3->clk);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- return -ENODEV;
- }
-
puv3->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(puv3->base))
return PTR_ERR(puv3->base);
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index dee6ab55..dc97175 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -147,11 +147,6 @@ static int pwm_probe(struct platform_device *pdev)
pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- return -ENODEV;
- }
-
pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(pwm->mmio_base))
return PTR_ERR(pwm->mmio_base);
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index 3d75f4a..a540293 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -181,11 +181,6 @@ static int tegra_pwm_probe(struct platform_device *pdev)
pwm->dev = &pdev->dev;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "no memory resources defined\n");
- return -ENODEV;
- }
-
pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(pwm->mmio_base))
return PTR_ERR(pwm->mmio_base);
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 0d65fb2..72ca42d 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -240,11 +240,6 @@ static int ecap_pwm_probe(struct platform_device *pdev)
pc->chip.npwm = 1;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- return -ENODEV;
- }
-
pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(pc->mmio_base))
return PTR_ERR(pc->mmio_base);
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 6a21759..48a485c 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -471,11 +471,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
pc->chip.npwm = NUM_PWM_CHANNEL;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- return -ENODEV;
- }
-
pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(pc->mmio_base))
return PTR_ERR(pc->mmio_base);
diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/pwm/pwm-tipwmss.c
index c9c3d3a..3b119bc 100644
--- a/drivers/pwm/pwm-tipwmss.c
+++ b/drivers/pwm/pwm-tipwmss.c
@@ -70,11 +70,6 @@ static int pwmss_probe(struct platform_device *pdev)
mutex_init(&info->pwmss_lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- return -ENODEV;
- }
-
info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(info->mmio_base))
return PTR_ERR(info->mmio_base);
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index 69effd1..323125a 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -230,11 +230,6 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (r == NULL) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- return -ENODEV;
- }
-
chip->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(chip->base))
return PTR_ERR(chip->base);
diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
index 6194d35..5ab0564 100644
--- a/drivers/rapidio/Kconfig
+++ b/drivers/rapidio/Kconfig
@@ -47,4 +47,24 @@ config RAPIDIO_DEBUG
If you are unsure about this, say N here.
+choice
+ prompt "Enumeration method"
+ depends on RAPIDIO
+ default RAPIDIO_ENUM_BASIC
+ help
+ There are different enumeration and discovery mechanisms offered
+ for RapidIO subsystem. You may select single built-in method or
+ or any number of methods to be built as modules.
+ Selecting a built-in method disables use of loadable methods.
+
+ If unsure, select Basic built-in.
+
+config RAPIDIO_ENUM_BASIC
+ tristate "Basic"
+ help
+ This option includes basic RapidIO fabric enumeration and discovery
+ mechanism similar to one described in RapidIO specification Annex 1.
+
+endchoice
+
source "drivers/rapidio/switches/Kconfig"
diff --git a/drivers/rapidio/Makefile b/drivers/rapidio/Makefile
index ec3fb81..3036702 100644
--- a/drivers/rapidio/Makefile
+++ b/drivers/rapidio/Makefile
@@ -1,7 +1,8 @@
#
# Makefile for RapidIO interconnect services
#
-obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o
+obj-y += rio.o rio-access.o rio-driver.o rio-sysfs.o
+obj-$(CONFIG_RAPIDIO_ENUM_BASIC) += rio-scan.o
obj-$(CONFIG_RAPIDIO) += switches/
obj-$(CONFIG_RAPIDIO) += devices/
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index 6faba40..a8b2c23 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -471,6 +471,10 @@ static irqreturn_t tsi721_irqhandler(int irq, void *ptr)
u32 intval;
u32 ch_inte;
+ /* For MSI mode disable all device-level interrupts */
+ if (priv->flags & TSI721_USING_MSI)
+ iowrite32(0, priv->regs + TSI721_DEV_INTE);
+
dev_int = ioread32(priv->regs + TSI721_DEV_INT);
if (!dev_int)
return IRQ_NONE;
@@ -560,6 +564,14 @@ static irqreturn_t tsi721_irqhandler(int irq, void *ptr)
}
}
#endif
+
+ /* For MSI mode re-enable device-level interrupts */
+ if (priv->flags & TSI721_USING_MSI) {
+ dev_int = TSI721_DEV_INT_SR2PC_CH | TSI721_DEV_INT_SRIO |
+ TSI721_DEV_INT_SMSG_CH | TSI721_DEV_INT_BDMA_CH;
+ iowrite32(dev_int, priv->regs + TSI721_DEV_INTE);
+ }
+
return IRQ_HANDLED;
}
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index 0f4a53b..a0c8755 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -164,6 +164,13 @@ void rio_unregister_driver(struct rio_driver *rdrv)
driver_unregister(&rdrv->driver);
}
+void rio_attach_device(struct rio_dev *rdev)
+{
+ rdev->dev.bus = &rio_bus_type;
+ rdev->dev.parent = &rio_bus;
+}
+EXPORT_SYMBOL_GPL(rio_attach_device);
+
/**
* rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure
* @dev: the standard device structure to match against
@@ -200,6 +207,7 @@ struct bus_type rio_bus_type = {
.name = "rapidio",
.match = rio_match_bus,
.dev_attrs = rio_dev_attrs,
+ .bus_attrs = rio_bus_attrs,
.probe = rio_device_probe,
.remove = rio_device_remove,
};
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index a965acd..4c15dbf 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -37,12 +37,8 @@
#include "rio.h"
-LIST_HEAD(rio_devices);
-
static void rio_init_em(struct rio_dev *rdev);
-DEFINE_SPINLOCK(rio_global_list_lock);
-
static int next_destid = 0;
static int next_comptag = 1;
@@ -327,127 +323,6 @@ static int rio_is_switch(struct rio_dev *rdev)
}
/**
- * rio_switch_init - Sets switch operations for a particular vendor switch
- * @rdev: RIO device
- * @do_enum: Enumeration/Discovery mode flag
- *
- * Searches the RIO switch ops table for known switch types. If the vid
- * and did match a switch table entry, then call switch initialization
- * routine to setup switch-specific routines.
- */
-static void rio_switch_init(struct rio_dev *rdev, int do_enum)
-{
- struct rio_switch_ops *cur = __start_rio_switch_ops;
- struct rio_switch_ops *end = __end_rio_switch_ops;
-
- while (cur < end) {
- if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
- pr_debug("RIO: calling init routine for %s\n",
- rio_name(rdev));
- cur->init_hook(rdev, do_enum);
- break;
- }
- cur++;
- }
-
- if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
- pr_debug("RIO: adding STD routing ops for %s\n",
- rio_name(rdev));
- rdev->rswitch->add_entry = rio_std_route_add_entry;
- rdev->rswitch->get_entry = rio_std_route_get_entry;
- rdev->rswitch->clr_table = rio_std_route_clr_table;
- }
-
- if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
- printk(KERN_ERR "RIO: missing routing ops for %s\n",
- rio_name(rdev));
-}
-
-/**
- * rio_add_device- Adds a RIO device to the device model
- * @rdev: RIO device
- *
- * Adds the RIO device to the global device list and adds the RIO
- * device to the RIO device list. Creates the generic sysfs nodes
- * for an RIO device.
- */
-static int rio_add_device(struct rio_dev *rdev)
-{
- int err;
-
- err = device_add(&rdev->dev);
- if (err)
- return err;
-
- spin_lock(&rio_global_list_lock);
- list_add_tail(&rdev->global_list, &rio_devices);
- spin_unlock(&rio_global_list_lock);
-
- rio_create_sysfs_dev_files(rdev);
-
- return 0;
-}
-
-/**
- * rio_enable_rx_tx_port - enable input receiver and output transmitter of
- * given port
- * @port: Master port associated with the RIO network
- * @local: local=1 select local port otherwise a far device is reached
- * @destid: Destination ID of the device to check host bit
- * @hopcount: Number of hops to reach the target
- * @port_num: Port (-number on switch) to enable on a far end device
- *
- * Returns 0 or 1 from on General Control Command and Status Register
- * (EXT_PTR+0x3C)
- */
-inline int rio_enable_rx_tx_port(struct rio_mport *port,
- int local, u16 destid,
- u8 hopcount, u8 port_num) {
-#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
- u32 regval;
- u32 ext_ftr_ptr;
-
- /*
- * enable rx input tx output port
- */
- pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = "
- "%d, port_num = %d)\n", local, destid, hopcount, port_num);
-
- ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount);
-
- if (local) {
- rio_local_read_config_32(port, ext_ftr_ptr +
- RIO_PORT_N_CTL_CSR(0),
- &regval);
- } else {
- if (rio_mport_read_config_32(port, destid, hopcount,
- ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), &regval) < 0)
- return -EIO;
- }
-
- if (regval & RIO_PORT_N_CTL_P_TYP_SER) {
- /* serial */
- regval = regval | RIO_PORT_N_CTL_EN_RX_SER
- | RIO_PORT_N_CTL_EN_TX_SER;
- } else {
- /* parallel */
- regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
- | RIO_PORT_N_CTL_EN_TX_PAR;
- }
-
- if (local) {
- rio_local_write_config_32(port, ext_ftr_ptr +
- RIO_PORT_N_CTL_CSR(0), regval);
- } else {
- if (rio_mport_write_config_32(port, destid, hopcount,
- ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0)
- return -EIO;
- }
-#endif
- return 0;
-}
-
-/**
* rio_setup_device- Allocates and sets up a RIO device
* @net: RIO network
* @port: Master port to send transactions
@@ -587,8 +462,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rdev->destid);
}
- rdev->dev.bus = &rio_bus_type;
- rdev->dev.parent = &rio_bus;
+ rio_attach_device(rdev);
device_initialize(&rdev->dev);
rdev->dev.release = rio_release_dev;
@@ -1260,19 +1134,30 @@ static void rio_pw_enable(struct rio_mport *port, int enable)
/**
* rio_enum_mport- Start enumeration through a master port
* @mport: Master port to send transactions
+ * @flags: Enumeration control flags
*
* Starts the enumeration process. If somebody has enumerated our
* master port device, then give up. If not and we have an active
* link, then start recursive peer enumeration. Returns %0 if
* enumeration succeeds or %-EBUSY if enumeration fails.
*/
-int rio_enum_mport(struct rio_mport *mport)
+int rio_enum_mport(struct rio_mport *mport, u32 flags)
{
struct rio_net *net = NULL;
int rc = 0;
printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id,
mport->name);
+
+ /*
+ * To avoid multiple start requests (repeat enumeration is not supported
+ * by this method) check if enumeration/discovery was performed for this
+ * mport: if mport was added into the list of mports for a net exit
+ * with error.
+ */
+ if (mport->nnode.next || mport->nnode.prev)
+ return -EBUSY;
+
/* If somebody else enumerated our master port device, bail. */
if (rio_enum_host(mport) < 0) {
printk(KERN_INFO
@@ -1362,14 +1247,16 @@ static void rio_build_route_tables(struct rio_net *net)
/**
* rio_disc_mport- Start discovery through a master port
* @mport: Master port to send transactions
+ * @flags: discovery control flags
*
* Starts the discovery process. If we have an active link,
- * then wait for the signal that enumeration is complete.
+ * then wait for the signal that enumeration is complete (if wait
+ * is allowed).
* When enumeration completion is signaled, start recursive
* peer discovery. Returns %0 if discovery succeeds or %-EBUSY
* on failure.
*/
-int rio_disc_mport(struct rio_mport *mport)
+int rio_disc_mport(struct rio_mport *mport, u32 flags)
{
struct rio_net *net = NULL;
unsigned long to_end;
@@ -1379,6 +1266,11 @@ int rio_disc_mport(struct rio_mport *mport)
/* If master port has an active link, allocate net and discover peers */
if (rio_mport_is_active(mport)) {
+ if (rio_enum_complete(mport))
+ goto enum_done;
+ else if (flags & RIO_SCAN_ENUM_NO_WAIT)
+ return -EAGAIN;
+
pr_debug("RIO: wait for enumeration to complete...\n");
to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ;
@@ -1421,3 +1313,41 @@ enum_done:
bail:
return -EBUSY;
}
+
+static struct rio_scan rio_scan_ops = {
+ .enumerate = rio_enum_mport,
+ .discover = rio_disc_mport,
+};
+
+static bool scan;
+module_param(scan, bool, 0);
+MODULE_PARM_DESC(scan, "Start RapidIO network enumeration/discovery "
+ "(default = 0)");
+
+/**
+ * rio_basic_attach:
+ *
+ * When this enumeration/discovery method is loaded as a module this function
+ * registers its specific enumeration and discover routines for all available
+ * RapidIO mport devices. The "scan" command line parameter controls ability of
+ * the module to start RapidIO enumeration/discovery automatically.
+ *
+ * Returns 0 for success or -EIO if unable to register itself.
+ *
+ * This enumeration/discovery method cannot be unloaded and therefore does not
+ * provide a matching cleanup_module routine.
+ */
+
+static int __init rio_basic_attach(void)
+{
+ if (rio_register_scan(RIO_MPORT_ANY, &rio_scan_ops))
+ return -EIO;
+ if (scan)
+ rio_init_mports();
+ return 0;
+}
+
+late_initcall(rio_basic_attach);
+
+MODULE_DESCRIPTION("Basic RapidIO enumeration/discovery");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 4dbe360..66d4acd 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -285,3 +285,48 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
}
}
+
+static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
+ size_t count)
+{
+ long val;
+ struct rio_mport *port = NULL;
+ int rc;
+
+ if (kstrtol(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ if (val == RIO_MPORT_ANY) {
+ rc = rio_init_mports();
+ goto exit;
+ }
+
+ if (val < 0 || val >= RIO_MAX_MPORTS)
+ return -EINVAL;
+
+ port = rio_find_mport((int)val);
+
+ if (!port) {
+ pr_debug("RIO: %s: mport_%d not available\n",
+ __func__, (int)val);
+ return -EINVAL;
+ }
+
+ if (!port->nscan)
+ return -EINVAL;
+
+ if (port->host_deviceid >= 0)
+ rc = port->nscan->enumerate(port, 0);
+ else
+ rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT);
+exit:
+ if (!rc)
+ rc = count;
+
+ return rc;
+}
+
+struct bus_attribute rio_bus_attrs[] = {
+ __ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store),
+ __ATTR_NULL
+};
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index d553b5d..cb1c089 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -31,7 +31,11 @@
#include "rio.h"
+static LIST_HEAD(rio_devices);
+static DEFINE_SPINLOCK(rio_global_list_lock);
+
static LIST_HEAD(rio_mports);
+static DEFINE_MUTEX(rio_mport_list_lock);
static unsigned char next_portid;
static DEFINE_SPINLOCK(rio_mmap_lock);
@@ -53,6 +57,32 @@ u16 rio_local_get_device_id(struct rio_mport *port)
}
/**
+ * rio_add_device- Adds a RIO device to the device model
+ * @rdev: RIO device
+ *
+ * Adds the RIO device to the global device list and adds the RIO
+ * device to the RIO device list. Creates the generic sysfs nodes
+ * for an RIO device.
+ */
+int rio_add_device(struct rio_dev *rdev)
+{
+ int err;
+
+ err = device_add(&rdev->dev);
+ if (err)
+ return err;
+
+ spin_lock(&rio_global_list_lock);
+ list_add_tail(&rdev->global_list, &rio_devices);
+ spin_unlock(&rio_global_list_lock);
+
+ rio_create_sysfs_dev_files(rdev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rio_add_device);
+
+/**
* rio_request_inb_mbox - request inbound mailbox service
* @mport: RIO master port from which to allocate the mailbox resource
* @dev_id: Device specific pointer to pass on event
@@ -489,6 +519,7 @@ rio_mport_get_physefb(struct rio_mport *port, int local,
return ext_ftr_ptr;
}
+EXPORT_SYMBOL_GPL(rio_mport_get_physefb);
/**
* rio_get_comptag - Begin or continue searching for a RIO device by component tag
@@ -521,6 +552,7 @@ exit:
spin_unlock(&rio_global_list_lock);
return rdev;
}
+EXPORT_SYMBOL_GPL(rio_get_comptag);
/**
* rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port.
@@ -545,6 +577,107 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
regval);
return 0;
}
+EXPORT_SYMBOL_GPL(rio_set_port_lockout);
+
+/**
+ * rio_switch_init - Sets switch operations for a particular vendor switch
+ * @rdev: RIO device
+ * @do_enum: Enumeration/Discovery mode flag
+ *
+ * Searches the RIO switch ops table for known switch types. If the vid
+ * and did match a switch table entry, then call switch initialization
+ * routine to setup switch-specific routines.
+ */
+void rio_switch_init(struct rio_dev *rdev, int do_enum)
+{
+ struct rio_switch_ops *cur = __start_rio_switch_ops;
+ struct rio_switch_ops *end = __end_rio_switch_ops;
+
+ while (cur < end) {
+ if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
+ pr_debug("RIO: calling init routine for %s\n",
+ rio_name(rdev));
+ cur->init_hook(rdev, do_enum);
+ break;
+ }
+ cur++;
+ }
+
+ if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
+ pr_debug("RIO: adding STD routing ops for %s\n",
+ rio_name(rdev));
+ rdev->rswitch->add_entry = rio_std_route_add_entry;
+ rdev->rswitch->get_entry = rio_std_route_get_entry;
+ rdev->rswitch->clr_table = rio_std_route_clr_table;
+ }
+
+ if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
+ printk(KERN_ERR "RIO: missing routing ops for %s\n",
+ rio_name(rdev));
+}
+EXPORT_SYMBOL_GPL(rio_switch_init);
+
+/**
+ * rio_enable_rx_tx_port - enable input receiver and output transmitter of
+ * given port
+ * @port: Master port associated with the RIO network
+ * @local: local=1 select local port otherwise a far device is reached
+ * @destid: Destination ID of the device to check host bit
+ * @hopcount: Number of hops to reach the target
+ * @port_num: Port (-number on switch) to enable on a far end device
+ *
+ * Returns 0 or 1 from on General Control Command and Status Register
+ * (EXT_PTR+0x3C)
+ */
+int rio_enable_rx_tx_port(struct rio_mport *port,
+ int local, u16 destid,
+ u8 hopcount, u8 port_num)
+{
+#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
+ u32 regval;
+ u32 ext_ftr_ptr;
+
+ /*
+ * enable rx input tx output port
+ */
+ pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = "
+ "%d, port_num = %d)\n", local, destid, hopcount, port_num);
+
+ ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount);
+
+ if (local) {
+ rio_local_read_config_32(port, ext_ftr_ptr +
+ RIO_PORT_N_CTL_CSR(0),
+ &regval);
+ } else {
+ if (rio_mport_read_config_32(port, destid, hopcount,
+ ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), &regval) < 0)
+ return -EIO;
+ }
+
+ if (regval & RIO_PORT_N_CTL_P_TYP_SER) {
+ /* serial */
+ regval = regval | RIO_PORT_N_CTL_EN_RX_SER
+ | RIO_PORT_N_CTL_EN_TX_SER;
+ } else {
+ /* parallel */
+ regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
+ | RIO_PORT_N_CTL_EN_TX_PAR;
+ }
+
+ if (local) {
+ rio_local_write_config_32(port, ext_ftr_ptr +
+ RIO_PORT_N_CTL_CSR(0), regval);
+ } else {
+ if (rio_mport_write_config_32(port, destid, hopcount,
+ ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0)
+ return -EIO;
+ }
+#endif
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rio_enable_rx_tx_port);
+
/**
* rio_chk_dev_route - Validate route to the specified device.
@@ -610,6 +743,7 @@ rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount)
return 0;
}
+EXPORT_SYMBOL_GPL(rio_mport_chk_dev_access);
/**
* rio_chk_dev_access - Validate access to the specified device.
@@ -941,6 +1075,7 @@ rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
return RIO_GET_BLOCK_ID(reg_val);
}
}
+EXPORT_SYMBOL_GPL(rio_mport_get_efb);
/**
* rio_mport_get_feature - query for devices' extended features
@@ -997,6 +1132,7 @@ rio_mport_get_feature(struct rio_mport * port, int local, u16 destid,
return 0;
}
+EXPORT_SYMBOL_GPL(rio_mport_get_feature);
/**
* rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did
@@ -1246,6 +1382,95 @@ EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg);
#endif /* CONFIG_RAPIDIO_DMA_ENGINE */
+/**
+ * rio_find_mport - find RIO mport by its ID
+ * @mport_id: number (ID) of mport device
+ *
+ * Given a RIO mport number, the desired mport is located
+ * in the global list of mports. If the mport is found, a pointer to its
+ * data structure is returned. If no mport is found, %NULL is returned.
+ */
+struct rio_mport *rio_find_mport(int mport_id)
+{
+ struct rio_mport *port;
+
+ mutex_lock(&rio_mport_list_lock);
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->id == mport_id)
+ goto found;
+ }
+ port = NULL;
+found:
+ mutex_unlock(&rio_mport_list_lock);
+
+ return port;
+}
+
+/**
+ * rio_register_scan - enumeration/discovery method registration interface
+ * @mport_id: mport device ID for which fabric scan routine has to be set
+ * (RIO_MPORT_ANY = set for all available mports)
+ * @scan_ops: enumeration/discovery control structure
+ *
+ * Assigns enumeration or discovery method to the specified mport device (or all
+ * available mports if RIO_MPORT_ANY is specified).
+ * Returns error if the mport already has an enumerator attached to it.
+ * In case of RIO_MPORT_ANY ignores ports with valid scan routines and returns
+ * an error if was unable to find at least one available mport.
+ */
+int rio_register_scan(int mport_id, struct rio_scan *scan_ops)
+{
+ struct rio_mport *port;
+ int rc = -EBUSY;
+
+ mutex_lock(&rio_mport_list_lock);
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
+ if (port->nscan && mport_id == RIO_MPORT_ANY)
+ continue;
+ else if (port->nscan)
+ break;
+
+ port->nscan = scan_ops;
+ rc = 0;
+
+ if (mport_id != RIO_MPORT_ANY)
+ break;
+ }
+ }
+ mutex_unlock(&rio_mport_list_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rio_register_scan);
+
+/**
+ * rio_unregister_scan - removes enumeration/discovery method from mport
+ * @mport_id: mport device ID for which fabric scan routine has to be
+ * unregistered (RIO_MPORT_ANY = set for all available mports)
+ *
+ * Removes enumeration or discovery method assigned to the specified mport
+ * device (or all available mports if RIO_MPORT_ANY is specified).
+ */
+int rio_unregister_scan(int mport_id)
+{
+ struct rio_mport *port;
+
+ mutex_lock(&rio_mport_list_lock);
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
+ if (port->nscan)
+ port->nscan = NULL;
+ if (mport_id != RIO_MPORT_ANY)
+ break;
+ }
+ }
+ mutex_unlock(&rio_mport_list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rio_unregister_scan);
+
static void rio_fixup_device(struct rio_dev *dev)
{
}
@@ -1274,7 +1499,7 @@ static void disc_work_handler(struct work_struct *_work)
work = container_of(_work, struct rio_disc_work, work);
pr_debug("RIO: discovery work for mport %d %s\n",
work->mport->id, work->mport->name);
- rio_disc_mport(work->mport);
+ work->mport->nscan->discover(work->mport, 0);
}
int rio_init_mports(void)
@@ -1290,12 +1515,15 @@ int rio_init_mports(void)
* First, run enumerations and check if we need to perform discovery
* on any of the registered mports.
*/
+ mutex_lock(&rio_mport_list_lock);
list_for_each_entry(port, &rio_mports, node) {
- if (port->host_deviceid >= 0)
- rio_enum_mport(port);
- else
+ if (port->host_deviceid >= 0) {
+ if (port->nscan)
+ port->nscan->enumerate(port, 0);
+ } else
n++;
}
+ mutex_unlock(&rio_mport_list_lock);
if (!n)
goto no_disc;
@@ -1322,14 +1550,16 @@ int rio_init_mports(void)
}
n = 0;
+ mutex_lock(&rio_mport_list_lock);
list_for_each_entry(port, &rio_mports, node) {
- if (port->host_deviceid < 0) {
+ if (port->host_deviceid < 0 && port->nscan) {
work[n].mport = port;
INIT_WORK(&work[n].work, disc_work_handler);
queue_work(rio_wq, &work[n].work);
n++;
}
}
+ mutex_unlock(&rio_mport_list_lock);
flush_workqueue(rio_wq);
pr_debug("RIO: destroy discovery workqueue\n");
@@ -1342,8 +1572,6 @@ no_disc:
return 0;
}
-device_initcall_sync(rio_init_mports);
-
static int hdids[RIO_MAX_MPORTS + 1];
static int rio_get_hdid(int index)
@@ -1371,7 +1599,10 @@ int rio_register_mport(struct rio_mport *port)
port->id = next_portid++;
port->host_deviceid = rio_get_hdid(port->id);
+ port->nscan = NULL;
+ mutex_lock(&rio_mport_list_lock);
list_add_tail(&port->node, &rio_mports);
+ mutex_unlock(&rio_mport_list_lock);
return 0;
}
@@ -1386,3 +1617,4 @@ EXPORT_SYMBOL_GPL(rio_request_inb_mbox);
EXPORT_SYMBOL_GPL(rio_release_inb_mbox);
EXPORT_SYMBOL_GPL(rio_request_outb_mbox);
EXPORT_SYMBOL_GPL(rio_release_outb_mbox);
+EXPORT_SYMBOL_GPL(rio_init_mports);
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index b1af414..c14f864 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -15,6 +15,7 @@
#include <linux/rio.h>
#define RIO_MAX_CHK_RETRY 3
+#define RIO_MPORT_ANY (-1)
/* Functions internal to the RIO core code */
@@ -27,8 +28,6 @@ extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid,
u8 hopcount);
extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
-extern int rio_enum_mport(struct rio_mport *mport);
-extern int rio_disc_mport(struct rio_mport *mport);
extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid,
u8 hopcount, u16 table, u16 route_destid,
u8 route_port);
@@ -39,10 +38,18 @@ extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
u8 hopcount, u16 table);
extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from);
+extern int rio_add_device(struct rio_dev *rdev);
+extern void rio_switch_init(struct rio_dev *rdev, int do_enum);
+extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid,
+ u8 hopcount, u8 port_num);
+extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops);
+extern int rio_unregister_scan(int mport_id);
+extern void rio_attach_device(struct rio_dev *rdev);
+extern struct rio_mport *rio_find_mport(int mport_id);
/* Structures internal to the RIO core code */
extern struct device_attribute rio_dev_attrs[];
-extern spinlock_t rio_global_list_lock;
+extern struct bus_attribute rio_bus_attrs[];
extern struct rio_switch_ops __start_rio_switch_ops[];
extern struct rio_switch_ops __end_rio_switch_ops[];
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 6e50178..815d6df 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1539,7 +1539,10 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev)
}
/**
- * Balance enable_count of each GPIO and actual GPIO pin control.
+ * regulator_ena_gpio_ctrl - balance enable_count of each GPIO and actual GPIO pin control
+ * @rdev: regulator_dev structure
+ * @enable: enable GPIO at initial use?
+ *
* GPIO is enabled in case of initial use. (enable_count is 0)
* GPIO is disabled when it is not shared any more. (enable_count <= 1)
*/
@@ -2702,7 +2705,7 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage);
/**
* regulator_set_current_limit - set regulator output current limit
* @regulator: regulator source
- * @min_uA: Minimuum supported current in uA
+ * @min_uA: Minimum supported current in uA
* @max_uA: Maximum supported current in uA
*
* Sets current sink to the desired output current. This can be set during
diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c
index 89bd2fa..ce89f78 100644
--- a/drivers/regulator/dbx500-prcmu.c
+++ b/drivers/regulator/dbx500-prcmu.c
@@ -24,18 +24,6 @@
static int power_state_active_cnt; /* will initialize to zero */
static DEFINE_SPINLOCK(power_state_active_lock);
-int power_state_active_get(void)
-{
- unsigned long flags;
- int cnt;
-
- spin_lock_irqsave(&power_state_active_lock, flags);
- cnt = power_state_active_cnt;
- spin_unlock_irqrestore(&power_state_active_lock, flags);
-
- return cnt;
-}
-
void power_state_active_enable(void)
{
unsigned long flags;
@@ -65,6 +53,18 @@ out:
#ifdef CONFIG_REGULATOR_DEBUG
+static int power_state_active_get(void)
+{
+ unsigned long flags;
+ int cnt;
+
+ spin_lock_irqsave(&power_state_active_lock, flags);
+ cnt = power_state_active_cnt;
+ spin_unlock_irqrestore(&power_state_active_lock, flags);
+
+ return cnt;
+}
+
static struct ux500_regulator_debug {
struct dentry *dir;
struct dentry *status_file;
diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c
index 92ceed0..3ae44ac 100644
--- a/drivers/regulator/palmas-regulator.c
+++ b/drivers/regulator/palmas-regulator.c
@@ -840,7 +840,7 @@ static int palmas_regulators_probe(struct platform_device *pdev)
break;
}
- if ((id == PALMAS_REG_SMPS6) && (id == PALMAS_REG_SMPS8))
+ if ((id == PALMAS_REG_SMPS6) || (id == PALMAS_REG_SMPS8))
ramp_delay_support = true;
if (ramp_delay_support) {
@@ -878,7 +878,7 @@ static int palmas_regulators_probe(struct platform_device *pdev)
pmic->desc[id].vsel_mask = SMPS10_VSEL;
pmic->desc[id].enable_reg =
PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
- PALMAS_SMPS10_STATUS);
+ PALMAS_SMPS10_CTRL);
pmic->desc[id].enable_mask = SMPS10_BOOST_EN;
pmic->desc[id].min_uV = 3750000;
pmic->desc[id].uV_step = 1250000;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 0c81915..b983813 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -20,7 +20,6 @@ if RTC_CLASS
config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume"
default y
- depends on !ALWAYS_USE_PERSISTENT_CLOCK
help
If you say yes here, the system time (wall clock) will be set using
the value read from a specified RTC device. This is useful to avoid
@@ -29,7 +28,6 @@ config RTC_HCTOSYS
config RTC_SYSTOHC
bool "Set the RTC time based on NTP synchronization"
default y
- depends on !ALWAYS_USE_PERSISTENT_CLOCK
help
If you say yes here, the system time (wall clock) will be stored
in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 0eab77b..f296f3f 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -25,6 +25,7 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/interrupt.h>
+#include <linux/spinlock.h>
#include <linux/ioctl.h>
#include <linux/completion.h>
#include <linux/io.h>
@@ -42,10 +43,65 @@
#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
+struct at91_rtc_config {
+ bool use_shadow_imr;
+};
+
+static const struct at91_rtc_config *at91_rtc_config;
static DECLARE_COMPLETION(at91_rtc_updated);
static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
static void __iomem *at91_rtc_regs;
static int irq;
+static DEFINE_SPINLOCK(at91_rtc_lock);
+static u32 at91_rtc_shadow_imr;
+
+static void at91_rtc_write_ier(u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&at91_rtc_lock, flags);
+ at91_rtc_shadow_imr |= mask;
+ at91_rtc_write(AT91_RTC_IER, mask);
+ spin_unlock_irqrestore(&at91_rtc_lock, flags);
+}
+
+static void at91_rtc_write_idr(u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&at91_rtc_lock, flags);
+ at91_rtc_write(AT91_RTC_IDR, mask);
+ /*
+ * Register read back (of any RTC-register) needed to make sure
+ * IDR-register write has reached the peripheral before updating
+ * shadow mask.
+ *
+ * Note that there is still a possibility that the mask is updated
+ * before interrupts have actually been disabled in hardware. The only
+ * way to be certain would be to poll the IMR-register, which is is
+ * the very register we are trying to emulate. The register read back
+ * is a reasonable heuristic.
+ */
+ at91_rtc_read(AT91_RTC_SR);
+ at91_rtc_shadow_imr &= ~mask;
+ spin_unlock_irqrestore(&at91_rtc_lock, flags);
+}
+
+static u32 at91_rtc_read_imr(void)
+{
+ unsigned long flags;
+ u32 mask;
+
+ if (at91_rtc_config->use_shadow_imr) {
+ spin_lock_irqsave(&at91_rtc_lock, flags);
+ mask = at91_rtc_shadow_imr;
+ spin_unlock_irqrestore(&at91_rtc_lock, flags);
+ } else {
+ mask = at91_rtc_read(AT91_RTC_IMR);
+ }
+
+ return mask;
+}
/*
* Decode time/date into rtc_time structure
@@ -110,9 +166,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
cr = at91_rtc_read(AT91_RTC_CR);
at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
- at91_rtc_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
+ at91_rtc_write_ier(AT91_RTC_ACKUPD);
wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
+ at91_rtc_write_idr(AT91_RTC_ACKUPD);
at91_rtc_write(AT91_RTC_TIMR,
bin2bcd(tm->tm_sec) << 0
@@ -144,7 +200,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = at91_alarm_year - 1900;
- alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
+ alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM)
? 1 : 0;
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
@@ -169,7 +225,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
tm.tm_min = alrm->time.tm_min;
tm.tm_sec = alrm->time.tm_sec;
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+ at91_rtc_write_idr(AT91_RTC_ALARM);
at91_rtc_write(AT91_RTC_TIMALR,
bin2bcd(tm.tm_sec) << 0
| bin2bcd(tm.tm_min) << 8
@@ -182,7 +238,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
if (alrm->enabled) {
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
- at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
+ at91_rtc_write_ier(AT91_RTC_ALARM);
}
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
@@ -198,9 +254,9 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
if (enabled) {
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
- at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
+ at91_rtc_write_ier(AT91_RTC_ALARM);
} else
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+ at91_rtc_write_idr(AT91_RTC_ALARM);
return 0;
}
@@ -209,7 +265,7 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
*/
static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
{
- unsigned long imr = at91_rtc_read(AT91_RTC_IMR);
+ unsigned long imr = at91_rtc_read_imr();
seq_printf(seq, "update_IRQ\t: %s\n",
(imr & AT91_RTC_ACKUPD) ? "yes" : "no");
@@ -229,7 +285,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
unsigned int rtsr;
unsigned long events = 0;
- rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read(AT91_RTC_IMR);
+ rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr();
if (rtsr) { /* this interrupt is shared! Is it ours? */
if (rtsr & AT91_RTC_ALARM)
events |= (RTC_AF | RTC_IRQF);
@@ -250,6 +306,43 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
return IRQ_NONE; /* not handled */
}
+static const struct at91_rtc_config at91rm9200_config = {
+};
+
+static const struct at91_rtc_config at91sam9x5_config = {
+ .use_shadow_imr = true,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id at91_rtc_dt_ids[] = {
+ {
+ .compatible = "atmel,at91rm9200-rtc",
+ .data = &at91rm9200_config,
+ }, {
+ .compatible = "atmel,at91sam9x5-rtc",
+ .data = &at91sam9x5_config,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
+#endif
+
+static const struct at91_rtc_config *
+at91_rtc_get_config(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+
+ if (pdev->dev.of_node) {
+ match = of_match_node(at91_rtc_dt_ids, pdev->dev.of_node);
+ if (!match)
+ return NULL;
+ return (const struct at91_rtc_config *)match->data;
+ }
+
+ return &at91rm9200_config;
+}
+
static const struct rtc_class_ops at91_rtc_ops = {
.read_time = at91_rtc_readtime,
.set_time = at91_rtc_settime,
@@ -268,6 +361,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
struct resource *regs;
int ret = 0;
+ at91_rtc_config = at91_rtc_get_config(pdev);
+ if (!at91_rtc_config)
+ return -ENODEV;
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_err(&pdev->dev, "no mmio resource defined\n");
@@ -290,7 +387,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
at91_rtc_write(AT91_RTC_MR, 0); /* 24 hour mode */
/* Disable all interrupts */
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM |
AT91_RTC_SECEV | AT91_RTC_TIMEV |
AT91_RTC_CALEV);
@@ -335,7 +432,7 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
struct rtc_device *rtc = platform_get_drvdata(pdev);
/* Disable all interrupts */
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM |
AT91_RTC_SECEV | AT91_RTC_TIMEV |
AT91_RTC_CALEV);
free_irq(irq, pdev);
@@ -358,13 +455,13 @@ static int at91_rtc_suspend(struct device *dev)
/* this IRQ is shared with DBGU and other hardware which isn't
* necessarily doing PM like we are...
*/
- at91_rtc_imr = at91_rtc_read(AT91_RTC_IMR)
+ at91_rtc_imr = at91_rtc_read_imr()
& (AT91_RTC_ALARM|AT91_RTC_SECEV);
if (at91_rtc_imr) {
if (device_may_wakeup(dev))
enable_irq_wake(irq);
else
- at91_rtc_write(AT91_RTC_IDR, at91_rtc_imr);
+ at91_rtc_write_idr(at91_rtc_imr);
}
return 0;
}
@@ -375,7 +472,7 @@ static int at91_rtc_resume(struct device *dev)
if (device_may_wakeup(dev))
disable_irq_wake(irq);
else
- at91_rtc_write(AT91_RTC_IER, at91_rtc_imr);
+ at91_rtc_write_ier(at91_rtc_imr);
}
return 0;
}
@@ -383,12 +480,6 @@ static int at91_rtc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
-static const struct of_device_id at91_rtc_dt_ids[] = {
- { .compatible = "atmel,at91rm9200-rtc" },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
-
static struct platform_driver at91_rtc_driver = {
.remove = __exit_p(at91_rtc_remove),
.driver = {
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index cc5bea9..f1cb706 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -854,6 +854,9 @@ static int cmos_resume(struct device *dev)
}
spin_lock_irq(&rtc_lock);
+ if (device_may_wakeup(dev))
+ hpet_rtc_timer_init();
+
do {
CMOS_WRITE(tmp, RTC_CONTROL);
hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK);
@@ -869,7 +872,6 @@ static int cmos_resume(struct device *dev)
rtc_update_irq(cmos->rtc, 1, mask);
tmp &= ~RTC_AIE;
hpet_mask_rtc_irq_bit(RTC_AIE);
- hpet_rtc_timer_init();
} while (mask & RTC_AIE);
spin_unlock_irq(&rtc_lock);
}
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c
index 48b6612..d5af7ba 100644
--- a/drivers/rtc/rtc-max8998.c
+++ b/drivers/rtc/rtc-max8998.c
@@ -285,7 +285,7 @@ static int max8998_rtc_probe(struct platform_device *pdev)
info->irq, ret);
dev_info(&pdev->dev, "RTC CHIP NAME: %s\n", pdev->id_entry->name);
- if (pdata->rtc_delay) {
+ if (pdata && pdata->rtc_delay) {
info->lp3974_bug_workaround = true;
dev_warn(&pdev->dev, "LP3974 with RTC REGERR option."
" RTC updates will be extremely slow.\n");
diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c
index f5dfb6e..d592e2f 100644
--- a/drivers/rtc/rtc-nuc900.c
+++ b/drivers/rtc/rtc-nuc900.c
@@ -234,11 +234,6 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "platform_get_resource failed\n");
- return -ENXIO;
- }
-
nuc900_rtc->rtc_reg = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nuc900_rtc->rtc_reg))
return PTR_ERR(nuc900_rtc->rtc_reg);
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 4e1bdb8..b0ba3fc 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -347,11 +347,6 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- pr_debug("%s: RTC resource data missing\n", pdev->name);
- return -ENOENT;
- }
-
rtc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(rtc_base))
return PTR_ERR(rtc_base);
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 8900ea7..0f0609b 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -306,7 +306,7 @@ static int pl031_remove(struct amba_device *adev)
struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
amba_set_drvdata(adev, NULL);
- free_irq(adev->irq[0], ldata->rtc);
+ free_irq(adev->irq[0], ldata);
rtc_device_unregister(ldata->rtc);
iounmap(ldata->base);
kfree(ldata);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 14040b2..0b495e8 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -477,11 +477,6 @@ static int s3c_rtc_probe(struct platform_device *pdev)
/* get the memory region */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get memory region resource\n");
- return -ENOENT;
- }
-
s3c_rtc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(s3c_rtc_base))
return PTR_ERR(s3c_rtc_base);
diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c
index a34315d..76af92a 100644
--- a/drivers/rtc/rtc-tegra.c
+++ b/drivers/rtc/rtc-tegra.c
@@ -322,12 +322,6 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev,
- "Unable to allocate resources for device.\n");
- return -EBUSY;
- }
-
info->rtc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->rtc_base))
return PTR_ERR(info->rtc_base);
diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c
index 459c2ff..426901c 100644
--- a/drivers/rtc/rtc-tps6586x.c
+++ b/drivers/rtc/rtc-tps6586x.c
@@ -273,6 +273,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
return ret;
}
+ device_init_wakeup(&pdev->dev, 1);
+
platform_set_drvdata(pdev, rtc);
rtc->rtc = devm_rtc_device_register(&pdev->dev, dev_name(&pdev->dev),
&tps6586x_rtc_ops, THIS_MODULE);
@@ -292,7 +294,6 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
goto fail_rtc_register;
}
disable_irq(rtc->irq);
- device_set_wakeup_capable(&pdev->dev, 1);
return 0;
fail_rtc_register:
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 8751a52..b2eab34 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -524,6 +524,7 @@ static int twl_rtc_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, rtc);
+ device_init_wakeup(&pdev->dev, 1);
return 0;
out2:
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 4361d97..d72a9216e 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -3440,8 +3440,16 @@ void dasd_generic_path_event(struct ccw_device *cdev, int *path_event)
device->path_data.opm &= ~eventlpm;
device->path_data.ppm &= ~eventlpm;
device->path_data.npm &= ~eventlpm;
- if (oldopm && !device->path_data.opm)
- dasd_generic_last_path_gone(device);
+ if (oldopm && !device->path_data.opm) {
+ dev_warn(&device->cdev->dev,
+ "No verified channel paths remain "
+ "for the device\n");
+ DBF_DEV_EVENT(DBF_WARNING, device,
+ "%s", "last verified path gone");
+ dasd_eer_write(device, NULL, DASD_EER_NOPATH);
+ dasd_device_set_stop_bits(device,
+ DASD_STOPPED_DC_WAIT);
+ }
}
if (path_event[chp] & PE_PATH_AVAILABLE) {
device->path_data.opm &= ~eventlpm;
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 690c333..464dd29 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -343,6 +343,7 @@ static int __init xpram_setup_blkdev(void)
put_disk(xpram_disks[i]);
goto out;
}
+ queue_flag_set_unlocked(QUEUE_FLAG_NONROT, xpram_queues[i]);
blk_queue_make_request(xpram_queues[i], xpram_make_request);
blk_queue_logical_block_size(xpram_queues[i], 4096);
}
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 21fabc6..6c440d4 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -352,12 +352,48 @@ static ssize_t chp_shared_show(struct device *dev,
static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
+static ssize_t chp_chid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct channel_path *chp = to_channelpath(dev);
+ ssize_t rc;
+
+ mutex_lock(&chp->lock);
+ if (chp->desc_fmt1.flags & 0x10)
+ rc = sprintf(buf, "%04x\n", chp->desc_fmt1.chid);
+ else
+ rc = 0;
+ mutex_unlock(&chp->lock);
+
+ return rc;
+}
+static DEVICE_ATTR(chid, 0444, chp_chid_show, NULL);
+
+static ssize_t chp_chid_external_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct channel_path *chp = to_channelpath(dev);
+ ssize_t rc;
+
+ mutex_lock(&chp->lock);
+ if (chp->desc_fmt1.flags & 0x10)
+ rc = sprintf(buf, "%x\n", chp->desc_fmt1.flags & 0x8 ? 1 : 0);
+ else
+ rc = 0;
+ mutex_unlock(&chp->lock);
+
+ return rc;
+}
+static DEVICE_ATTR(chid_external, 0444, chp_chid_external_show, NULL);
+
static struct attribute *chp_attrs[] = {
&dev_attr_status.attr,
&dev_attr_configure.attr,
&dev_attr_type.attr,
&dev_attr_cmg.attr,
&dev_attr_shared.attr,
+ &dev_attr_chid.attr,
+ &dev_attr_chid_external.attr,
NULL,
};
static struct attribute_group chp_attr_group = {
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 349d5fc..e7ef2a6 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -43,7 +43,9 @@ struct channel_path_desc_fmt1 {
u8 chpid;
u32:24;
u8 chpp;
- u32 unused[3];
+ u32 unused[2];
+ u16 chid;
+ u32:16;
u16 mdc;
u16:13;
u8 r:1;
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 4ffa66c..9ca3996 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -2040,6 +2040,7 @@ static struct net_device *netiucv_init_netdevice(char *username, char *userdata)
netiucv_setup_netdevice);
if (!dev)
return NULL;
+ rtnl_lock();
if (dev_alloc_name(dev, dev->name) < 0)
goto out_netdev;
@@ -2061,6 +2062,7 @@ static struct net_device *netiucv_init_netdevice(char *username, char *userdata)
out_fsm:
kfree_fsm(privptr->fsm);
out_netdev:
+ rtnl_unlock();
free_netdev(dev);
return NULL;
}
@@ -2100,6 +2102,7 @@ static ssize_t conn_write(struct device_driver *drv,
rc = netiucv_register_device(dev);
if (rc) {
+ rtnl_unlock();
IUCV_DBF_TEXT_(setup, 2,
"ret %d from netiucv_register_device\n", rc);
goto out_free_ndev;
@@ -2109,7 +2112,8 @@ static ssize_t conn_write(struct device_driver *drv,
priv = netdev_priv(dev);
SET_NETDEV_DEV(dev, priv->dev);
- rc = register_netdev(dev);
+ rc = register_netdevice(dev);
+ rtnl_unlock();
if (rc)
goto out_unreg;
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index 439c012..b63d534 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -186,7 +186,7 @@ bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
file->f_pos += offset;
break;
case 2:
- file->f_pos = debug->buffer_len - offset;
+ file->f_pos = debug->buffer_len + offset;
break;
default:
return -EINVAL;
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 3fecf35..9138d4e 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -358,7 +358,7 @@ static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb)
return DIV_ROUND_UP(skb->len, 8);
flits = skb_transport_offset(skb) / 8;
cnt = skb_shinfo(skb)->nr_frags;
- if (skb->tail != skb->transport_header)
+ if (skb_tail_pointer(skb) != skb_transport_header(skb))
cnt++;
return flits + sgl_len(cnt);
}
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 292b24f..ee721b6 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -1975,7 +1975,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
{
struct fcoe_ctlr_device *cdev;
struct fc_lport *lport = NULL;
- struct net_device *netdev = ptr;
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
struct fcoe_ctlr *ctlr;
struct fcoe_interface *fcoe;
struct fcoe_port *port;
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index f3a5a53..01adbe0 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -704,7 +704,7 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer)
static int libfcoe_device_notification(struct notifier_block *notifier,
ulong event, void *ptr)
{
- struct net_device *netdev = ptr;
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
switch (event) {
case NETDEV_UNREGISTER:
diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c
index adc1f7f..85e1ffd 100644
--- a/drivers/scsi/fnic/fnic_debugfs.c
+++ b/drivers/scsi/fnic/fnic_debugfs.c
@@ -174,7 +174,7 @@ static loff_t fnic_trace_debugfs_lseek(struct file *file,
pos = file->f_pos + offset;
break;
case 2:
- pos = fnic_dbg_prt->buffer_len - offset;
+ pos = fnic_dbg_prt->buffer_len + offset;
}
return (pos < 0 || pos > fnic_dbg_prt->buffer_len) ?
-EINVAL : (file->f_pos = pos);
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index f63f5ff..f525ecb 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -1178,7 +1178,7 @@ lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
pos = file->f_pos + off;
break;
case 2:
- pos = debug->len - off;
+ pos = debug->len + off;
}
return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos);
}
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index d182c96..7a3870f 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1370,7 +1370,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess)
dump_stack();
return;
}
- target_wait_for_sess_cmds(se_sess, 0);
+ target_wait_for_sess_cmds(se_sess);
transport_deregister_session_configfs(sess->se_sess);
transport_deregister_session(sess->se_sess);
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index db66357..86f0c5d 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -84,6 +84,7 @@ static int proc_scsi_host_open(struct inode *inode, struct file *file)
static const struct file_operations proc_scsi_fops = {
.open = proc_scsi_host_open,
+ .release = single_release,
.read = seq_read,
.llseek = seq_lseek,
.write = proc_scsi_host_write
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 787bd2c..380387a 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -526,13 +526,17 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master,
}
if (xfer->tx_buf)
- spi_writel(as, TDR, *(u8 *)(xfer->tx_buf));
+ if (xfer->bits_per_word > 8)
+ spi_writel(as, TDR, *(u16 *)(xfer->tx_buf));
+ else
+ spi_writel(as, TDR, *(u8 *)(xfer->tx_buf));
else
spi_writel(as, TDR, 0);
dev_dbg(master->dev.parent,
- " start pio xfer %p: len %u tx %p rx %p\n",
- xfer, xfer->len, xfer->tx_buf, xfer->rx_buf);
+ " start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
+ xfer, xfer->len, xfer->tx_buf, xfer->rx_buf,
+ xfer->bits_per_word);
/* Enable relevant interrupts */
spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES));
@@ -950,21 +954,39 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
{
u8 *txp;
u8 *rxp;
+ u16 *txp16;
+ u16 *rxp16;
unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
if (xfer->rx_buf) {
- rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
- *rxp = spi_readl(as, RDR);
+ if (xfer->bits_per_word > 8) {
+ rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos);
+ *rxp16 = spi_readl(as, RDR);
+ } else {
+ rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
+ *rxp = spi_readl(as, RDR);
+ }
} else {
spi_readl(as, RDR);
}
-
- as->current_remaining_bytes--;
+ if (xfer->bits_per_word > 8) {
+ as->current_remaining_bytes -= 2;
+ if (as->current_remaining_bytes < 0)
+ as->current_remaining_bytes = 0;
+ } else {
+ as->current_remaining_bytes--;
+ }
if (as->current_remaining_bytes) {
if (xfer->tx_buf) {
- txp = ((u8 *)xfer->tx_buf) + xfer_pos + 1;
- spi_writel(as, TDR, *txp);
+ if (xfer->bits_per_word > 8) {
+ txp16 = (u16 *)(((u8 *)xfer->tx_buf)
+ + xfer_pos + 2);
+ spi_writel(as, TDR, *txp16);
+ } else {
+ txp = ((u8 *)xfer->tx_buf) + xfer_pos + 1;
+ spi_writel(as, TDR, *txp);
+ }
} else {
spi_writel(as, TDR, 0);
}
@@ -1378,9 +1400,16 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
}
}
+ if (xfer->bits_per_word > 8) {
+ if (xfer->len % 2) {
+ dev_dbg(&spi->dev, "buffer len should be 16 bits aligned\n");
+ return -EINVAL;
+ }
+ }
+
/* FIXME implement these protocol options!! */
- if (xfer->speed_hz) {
- dev_dbg(&spi->dev, "no protocol options yet\n");
+ if (xfer->speed_hz < spi->max_speed_hz) {
+ dev_dbg(&spi->dev, "can't change speed in transfer\n");
return -ENOPROTOOPT;
}
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 2e8f24a..50b13c9 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -784,7 +784,7 @@ static const struct of_device_id davinci_spi_of_match[] = {
},
{ },
};
-MODULE_DEVICE_TABLE(of, davini_spi_of_match);
+MODULE_DEVICE_TABLE(of, davinci_spi_of_match);
/**
* spi_davinci_get_pdata - Get platform data from DTS binding
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index 60cfae5..eab593e 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -89,7 +89,7 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val)
if ((mask & hspi_read(hspi, SPSR)) == val)
return 0;
- msleep(20);
+ udelay(10);
}
dev_err(hspi->dev, "timeout\n");
diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c
index d65c000..09df8e2 100644
--- a/drivers/spi/spi-tegra20-sflash.c
+++ b/drivers/spi/spi-tegra20-sflash.c
@@ -489,11 +489,6 @@ static int tegra_sflash_probe(struct platform_device *pdev)
tegra_sflash_parse_dt(tsd);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "No IO memory resource\n");
- ret = -ENODEV;
- goto exit_free_master;
- }
tsd->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(tsd->base)) {
ret = PTR_ERR(tsd->base);
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index 35f60bd..637d728 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1487,7 +1487,7 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
return 0;
err_spi_register_master:
- free_irq(board_dat->pdev->irq, board_dat);
+ free_irq(board_dat->pdev->irq, data);
err_request_irq:
pch_spi_free_resources(board_dat, data);
err_spi_get_resources:
@@ -1667,6 +1667,7 @@ static int pch_spi_probe(struct pci_dev *pdev,
pd_dev = platform_device_alloc("pch-spi", i);
if (!pd_dev) {
dev_err(&pdev->dev, "platform_device_alloc failed\n");
+ retval = -ENOMEM;
goto err_platform_device;
}
pd_dev_save->pd_save[i] = pd_dev;
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index e1d7696..34d18dc 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -267,7 +267,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
u32 ipif_ier;
- u16 cr;
/* We get here with transmitter inhibited */
@@ -276,7 +275,6 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
xspi->remaining_bytes = t->len;
INIT_COMPLETION(xspi->done);
- xilinx_spi_fill_tx_fifo(xspi);
/* Enable the transmit empty interrupt, which we use to determine
* progress on the transmission.
@@ -285,12 +283,41 @@ static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY,
xspi->regs + XIPIF_V123B_IIER_OFFSET);
- /* Start the transfer by not inhibiting the transmitter any longer */
- cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) &
- ~XSPI_CR_TRANS_INHIBIT;
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
+ for (;;) {
+ u16 cr;
+ u8 sr;
+
+ xilinx_spi_fill_tx_fifo(xspi);
+
+ /* Start the transfer by not inhibiting the transmitter any
+ * longer
+ */
+ cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) &
+ ~XSPI_CR_TRANS_INHIBIT;
+ xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
+
+ wait_for_completion(&xspi->done);
+
+ /* A transmit has just completed. Process received data and
+ * check for more data to transmit. Always inhibit the
+ * transmitter while the Isr refills the transmit register/FIFO,
+ * or make sure it is stopped if we're done.
+ */
+ cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
+ xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
+ xspi->regs + XSPI_CR_OFFSET);
+
+ /* Read out all the data from the Rx FIFO */
+ sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
+ while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
+ xspi->rx_fn(xspi);
+ sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
+ }
- wait_for_completion(&xspi->done);
+ /* See if there is more data to send */
+ if (!xspi->remaining_bytes > 0)
+ break;
+ }
/* Disable the transmit empty interrupt */
xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET);
@@ -314,38 +341,7 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
- u16 cr;
- u8 sr;
-
- /* A transmit has just completed. Process received data and
- * check for more data to transmit. Always inhibit the
- * transmitter while the Isr refills the transmit register/FIFO,
- * or make sure it is stopped if we're done.
- */
- cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
- xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
- xspi->regs + XSPI_CR_OFFSET);
-
- /* Read out all the data from the Rx FIFO */
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
- xspi->rx_fn(xspi);
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- }
-
- /* See if there is more data to send */
- if (xspi->remaining_bytes > 0) {
- xilinx_spi_fill_tx_fifo(xspi);
- /* Start the transfer by not inhibiting the
- * transmitter any longer
- */
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
- } else {
- /* No more data to send.
- * Indicate the transfer is completed.
- */
- complete(&xspi->done);
- }
+ complete(&xspi->done);
}
return IRQ_HANDLED;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 163fd80..32b7bb1 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -334,7 +334,7 @@ struct spi_device *spi_alloc_device(struct spi_master *master)
spi->dev.parent = &master->dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
- spi->cs_gpio = -EINVAL;
+ spi->cs_gpio = -ENOENT;
device_initialize(&spi->dev);
return spi;
}
@@ -1067,8 +1067,11 @@ static int of_spi_register_master(struct spi_master *master)
nb = of_gpio_named_count(np, "cs-gpios");
master->num_chipselect = max(nb, (int)master->num_chipselect);
- if (nb < 1)
+ /* Return error only for an incorrectly formed cs-gpios property */
+ if (nb == 0 || nb == -ENOENT)
return 0;
+ else if (nb < 0)
+ return nb;
cs = devm_kzalloc(&master->dev,
sizeof(int) * master->num_chipselect,
@@ -1079,7 +1082,7 @@ static int of_spi_register_master(struct spi_master *master)
return -ENOMEM;
for (i = 0; i < master->num_chipselect; i++)
- cs[i] = -EINVAL;
+ cs[i] = -ENOENT;
for (i = 0; i < nb; i++)
cs[i] = of_get_named_gpio(np, "cs-gpios", i);
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
index a3b2364..e753fbe 100644
--- a/drivers/ssb/sprom.c
+++ b/drivers/ssb/sprom.c
@@ -54,7 +54,7 @@ static int hex2sprom(u16 *sprom, const char *dump, size_t len,
while (cnt < sprom_size_words) {
memcpy(tmp, dump, 4);
dump += 4;
- err = strict_strtoul(tmp, 16, &parsed);
+ err = kstrtoul(tmp, 16, &parsed);
if (err)
return err;
sprom[cnt++] = swab16((u16)parsed);
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 4e8a179..aefe820 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -72,10 +72,10 @@ source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
-source "drivers/staging/zram/Kconfig"
-
source "drivers/staging/zsmalloc/Kconfig"
+source "drivers/staging/zram/Kconfig"
+
source "drivers/staging/wlags49_h2/Kconfig"
source "drivers/staging/wlags49_h25/Kconfig"
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
index ceb1c64..6dc27da 100644
--- a/drivers/staging/android/alarm-dev.c
+++ b/drivers/staging/android/alarm-dev.c
@@ -264,6 +264,8 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
rv = alarm_do_ioctl(file, cmd, &ts);
+ if (rv)
+ return rv;
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_ALARM_GET_TIME(0):
@@ -272,7 +274,7 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
- return rv;
+ return 0;
}
#ifdef CONFIG_COMPAT
static long alarm_compat_ioctl(struct file *file, unsigned int cmd,
@@ -295,6 +297,8 @@ static long alarm_compat_ioctl(struct file *file, unsigned int cmd,
}
rv = alarm_do_ioctl(file, cmd, &ts);
+ if (rv)
+ return rv;
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_ALARM_GET_TIME(0): /* NOTE: we modified cmd above */
@@ -303,7 +307,7 @@ static long alarm_compat_ioctl(struct file *file, unsigned int cmd,
break;
}
- return rv;
+ return 0;
}
#endif
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index b040200..9bd8747 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -242,7 +242,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
* 'log->buffer' which contains the first entry readable by 'euid'
*/
static size_t get_next_entry_by_uid(struct logger_log *log,
- size_t off, uid_t euid)
+ size_t off, kuid_t euid)
{
while (off != log->w_off) {
struct logger_entry *entry;
@@ -251,7 +251,7 @@ static size_t get_next_entry_by_uid(struct logger_log *log,
entry = get_entry_header(log, off, &scratch);
- if (entry->euid == euid)
+ if (uid_eq(entry->euid, euid))
return off;
next_len = sizeof(struct logger_entry) + entry->len;
diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h
index cc6bbd9..70af7d8 100644
--- a/drivers/staging/android/logger.h
+++ b/drivers/staging/android/logger.h
@@ -66,7 +66,7 @@ struct logger_entry {
__s32 tid;
__s32 sec;
__s32 nsec;
- uid_t euid;
+ kuid_t euid;
char msg[0];
};
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 7871579..87e852a 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -981,6 +981,7 @@ config COMEDI_ME_DAQ
config COMEDI_NI_6527
tristate "NI 6527 support"
+ depends on HAS_DMA
select COMEDI_MITE
---help---
Enable support for the National Instruments 6527 PCI card
@@ -990,6 +991,7 @@ config COMEDI_NI_6527
config COMEDI_NI_65XX
tristate "NI 65xx static dio PCI card support"
+ depends on HAS_DMA
select COMEDI_MITE
---help---
Enable support for National Instruments 65xx static dio boards.
@@ -1003,6 +1005,7 @@ config COMEDI_NI_65XX
config COMEDI_NI_660X
tristate "NI 660x counter/timer PCI card support"
+ depends on HAS_DMA
select COMEDI_NI_TIOCMD
---help---
Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602,
@@ -1013,6 +1016,7 @@ config COMEDI_NI_660X
config COMEDI_NI_670X
tristate "NI 670x PCI card support"
+ depends on HAS_DMA
select COMEDI_MITE
---help---
Enable support for National Instruments PCI-6703 and PCI-6704
@@ -1022,6 +1026,7 @@ config COMEDI_NI_670X
config COMEDI_NI_LABPC_PCI
tristate "NI Lab-PC PCI-1200 support"
+ depends on HAS_DMA
select COMEDI_NI_LABPC
select COMEDI_MITE
---help---
@@ -1032,6 +1037,7 @@ config COMEDI_NI_LABPC_PCI
config COMEDI_NI_PCIDIO
tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support"
+ depends on HAS_DMA
select COMEDI_MITE
select COMEDI_8255
---help---
@@ -1043,6 +1049,7 @@ config COMEDI_NI_PCIDIO
config COMEDI_NI_PCIMIO
tristate "NI PCI-MIO-E series and M series support"
+ depends on HAS_DMA
select COMEDI_NI_TIOCMD
select COMEDI_8255
select COMEDI_FC
@@ -1095,10 +1102,12 @@ config COMEDI_SSV_DNP
called ssv_dnp.
config COMEDI_MITE
+ depends on HAS_DMA
tristate
config COMEDI_NI_TIOCMD
tristate
+ depends on HAS_DMA
select COMEDI_NI_TIO
select COMEDI_MITE
diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c
index ca70990..d4be0e6 100644
--- a/drivers/staging/comedi/comedi_buf.c
+++ b/drivers/staging/comedi/comedi_buf.c
@@ -51,10 +51,12 @@ static void __comedi_buf_free(struct comedi_device *dev,
clear_bit(PG_reserved,
&(virt_to_page(buf->virt_addr)->flags));
if (s->async_dma_dir != DMA_NONE) {
+#ifdef CONFIG_HAS_DMA
dma_free_coherent(dev->hw_dev,
PAGE_SIZE,
buf->virt_addr,
buf->dma_addr);
+#endif
} else {
free_page((unsigned long)buf->virt_addr);
}
@@ -74,6 +76,12 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
struct comedi_buf_page *buf;
unsigned i;
+ if (!IS_ENABLED(CONFIG_HAS_DMA) && s->async_dma_dir != DMA_NONE) {
+ dev_err(dev->class_dev,
+ "dma buffer allocation not supported\n");
+ return;
+ }
+
async->buf_page_list = vzalloc(sizeof(*buf) * n_pages);
if (async->buf_page_list)
pages = vmalloc(sizeof(struct page *) * n_pages);
@@ -84,11 +92,15 @@ static void __comedi_buf_alloc(struct comedi_device *dev,
for (i = 0; i < n_pages; i++) {
buf = &async->buf_page_list[i];
if (s->async_dma_dir != DMA_NONE)
+#ifdef CONFIG_HAS_DMA
buf->virt_addr = dma_alloc_coherent(dev->hw_dev,
PAGE_SIZE,
&buf->dma_addr,
GFP_KERNEL |
__GFP_COMP);
+#else
+ break;
+#endif
else
buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL);
if (!buf->virt_addr)
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 00f2547..924c54c 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -246,9 +246,6 @@ static int resize_async_buffer(struct comedi_device *dev,
return -EBUSY;
}
- if (!async->prealloc_buf)
- return -EINVAL;
-
/* make sure buffer is an integral number of pages
* (we round up) */
new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 3d978f3..77a7bb6 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -976,8 +976,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* clear flip-flop to make sure 2-byte registers for
* count and address get set correctly */
clear_dma_ff(devpriv->dma_chan);
- set_dma_addr(devpriv->dma_chan,
- virt_to_bus(devpriv->dma_buffer));
+ set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
/* set appropriate size of transfer */
devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
if (cmd->stop_src == TRIG_COUNT &&
@@ -1089,7 +1088,7 @@ static void labpc_drain_dma(struct comedi_device *dev)
devpriv->count -= num_points;
/* set address and count for next transfer */
- set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer));
+ set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
set_dma_count(devpriv->dma_chan, leftover * sample_size);
release_dma_lock(flags);
@@ -1741,6 +1740,9 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
unsigned long dma_flags;
devpriv->dma_chan = dma_chan;
+ devpriv->dma_addr =
+ virt_to_bus(devpriv->dma_buffer);
+
dma_flags = claim_dma_lock();
disable_dma(devpriv->dma_chan);
set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h
index 615f16f..4b691f5 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.h
+++ b/drivers/staging/comedi/drivers/ni_labpc.h
@@ -82,6 +82,7 @@ struct labpc_private {
unsigned int divisor_b1;
unsigned int dma_chan; /* dma channel to use */
u16 *dma_buffer; /* buffer ai will dma into */
+ phys_addr_t dma_addr;
/* transfer size in bytes for current transfer */
unsigned int dma_transfer_size;
/* we are using dma/fifo-half-full/etc. */
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index a46d579..8c5dee9 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -310,9 +310,11 @@ static int ni_gpct_insn_read(struct comedi_device *dev,
static int ni_gpct_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
+#ifdef PCIDMA
static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
static int ni_gpct_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd);
+#endif
static int ni_gpct_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
static void handle_gpct_interrupt(struct comedi_device *dev,
@@ -4617,9 +4619,7 @@ static int ni_E_init(struct comedi_device *dev)
for (j = 0; j < NUM_GPCT; ++j) {
s = &dev->subdevices[NI_GPCT_SUBDEV(j)];
s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags =
- SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ
- /* | SDF_CMD_WRITE */ ;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
s->n_chan = 3;
if (board->reg_type & ni_reg_m_series_mask)
s->maxdata = 0xffffffff;
@@ -4628,11 +4628,14 @@ static int ni_E_init(struct comedi_device *dev)
s->insn_read = &ni_gpct_insn_read;
s->insn_write = &ni_gpct_insn_write;
s->insn_config = &ni_gpct_insn_config;
+#ifdef PCIDMA
+ s->subdev_flags |= SDF_CMD_READ /* | SDF_CMD_WRITE */;
s->do_cmd = &ni_gpct_cmd;
s->len_chanlist = 1;
s->do_cmdtest = &ni_gpct_cmdtest;
s->cancel = &ni_gpct_cancel;
s->async_dma_dir = DMA_BIDIRECTIONAL;
+#endif
s->private = &devpriv->counter_dev->counters[j];
devpriv->counter_dev->counters[j].chip_index = 0;
@@ -5216,10 +5219,10 @@ static int ni_gpct_insn_write(struct comedi_device *dev,
return ni_tio_winsn(counter, insn, data);
}
+#ifdef PCIDMA
static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
int retval;
-#ifdef PCIDMA
struct ni_gpct *counter = s->private;
/* const struct comedi_cmd *cmd = &s->async->cmd; */
@@ -5233,23 +5236,20 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL);
ni_e_series_enable_second_irq(dev, counter->counter_index, 1);
retval = ni_tio_cmd(counter, s->async);
-#else
- retval = -ENOTSUPP;
-#endif
return retval;
}
+#endif
+#ifdef PCIDMA
static int ni_gpct_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_cmd *cmd)
{
-#ifdef PCIDMA
struct ni_gpct *counter = s->private;
return ni_tio_cmdtest(counter, cmd);
-#else
return -ENOTSUPP;
-#endif
}
+#endif
static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
diff --git a/drivers/staging/csr/netdev.c b/drivers/staging/csr/netdev.c
index a0177d9..d49cdf84a 100644
--- a/drivers/staging/csr/netdev.c
+++ b/drivers/staging/csr/netdev.c
@@ -2891,7 +2891,7 @@ void uf_net_get_name(struct net_device *dev, char *name, int len)
*/
static int
uf_netdev_event(struct notifier_block *notif, unsigned long event, void* ptr) {
- struct net_device *netdev = ptr;
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(netdev);
unifi_priv_t *priv = NULL;
static const CsrWifiMacAddress broadcast_address = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
diff --git a/drivers/staging/dwc2/Kconfig b/drivers/staging/dwc2/Kconfig
index f0b4739..d15d9d5 100644
--- a/drivers/staging/dwc2/Kconfig
+++ b/drivers/staging/dwc2/Kconfig
@@ -2,7 +2,6 @@ config USB_DWC2
tristate "DesignWare USB2 DRD Core Support"
depends on USB
depends on VIRT_TO_BUS
- select USB_OTG_UTILS
help
Say Y or M here if your system has a Dual Role HighSpeed
USB controller based on the DesignWare HSOTG IP Core.
@@ -39,6 +38,7 @@ config USB_DWC2_TRACK_MISSED_SOFS
bool "Enable Missed SOF Tracking"
help
Say Y here to enable logging of missed SOF events to the dmesg log.
+ WARNING: This feature is still experimental.
If in doubt, say N.
config USB_DWC2_DEBUG_PERIODIC
diff --git a/drivers/staging/dwc2/hcd.c b/drivers/staging/dwc2/hcd.c
index 827ab78..8551cce 100644
--- a/drivers/staging/dwc2/hcd.c
+++ b/drivers/staging/dwc2/hcd.c
@@ -2804,9 +2804,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
/* Set device flags indicating whether the HCD supports DMA */
if (hsotg->core_params->dma_enable > 0) {
- if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(31)) < 0)
- dev_warn(hsotg->dev,
- "can't enable workaround for >2GB RAM\n");
+ if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0)
+ dev_warn(hsotg->dev, "can't set DMA mask\n");
if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(31)) < 0)
dev_warn(hsotg->dev,
"can't enable workaround for >2GB RAM\n");
diff --git a/drivers/staging/dwc2/hcd_intr.c b/drivers/staging/dwc2/hcd_intr.c
index 6e5dbed..e24062f 100644
--- a/drivers/staging/dwc2/hcd_intr.c
+++ b/drivers/staging/dwc2/hcd_intr.c
@@ -56,8 +56,6 @@
static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg)
{
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
-#warning Compiling code to track missed SOFs
-
u16 curr_frame_number = hsotg->frame_number;
if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
diff --git a/drivers/staging/dwc2/platform.c b/drivers/staging/dwc2/platform.c
index 1f3d581..44cce2f 100644
--- a/drivers/staging/dwc2/platform.c
+++ b/drivers/staging/dwc2/platform.c
@@ -95,6 +95,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
hsotg->dev = &dev->dev;
+ /*
+ * Use reasonable defaults so platforms don't have to provide these.
+ */
+ if (!dev->dev.dma_mask)
+ dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+ if (!dev->dev.coherent_dma_mask)
+ dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
irq = platform_get_irq(dev, 0);
if (irq < 0) {
dev_err(&dev->dev, "missing IRQ resource\n");
@@ -102,11 +110,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
}
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&dev->dev, "missing memory base resource\n");
- return -EINVAL;
- }
-
hsotg->regs = devm_ioremap_resource(&dev->dev, res);
if (IS_ERR(hsotg->regs))
return PTR_ERR(hsotg->regs);
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
index 94e426e..b2330f1 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c
@@ -164,7 +164,7 @@ static const struct file_operations ft1000_proc_fops = {
static int ft1000NotifyProc(struct notifier_block *this, unsigned long event,
void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct ft1000_info *info;
info = netdev_priv(dev);
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
index eca6f02..5ead942 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
@@ -166,7 +166,7 @@ static const struct file_operations ft1000_proc_fops = {
static int
ft1000NotifyProc(struct notifier_block *this, unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct ft1000_info *info;
struct proc_dir_entry *ft1000_proc_file;
diff --git a/drivers/staging/gdm72xx/Kconfig b/drivers/staging/gdm72xx/Kconfig
index 3c18efe..6905913 100644
--- a/drivers/staging/gdm72xx/Kconfig
+++ b/drivers/staging/gdm72xx/Kconfig
@@ -39,7 +39,7 @@ if WIMAX_GDM72XX_USB
config WIMAX_GDM72XX_USB_PM
bool "Enable power managerment support"
- depends on USB_SUSPEND
+ depends on PM_RUNTIME
endif # WIMAX_GDM72XX_USB
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index 2856b8f..163c638 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -690,7 +690,6 @@ static void mxs_lradc_trigger_remove(struct iio_dev *iio)
static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
{
struct mxs_lradc *lradc = iio_priv(iio);
- struct iio_buffer *buffer = iio->buffer;
int ret = 0, chan, ofs = 0;
unsigned long enable = 0;
uint32_t ctrl4_set = 0;
@@ -698,7 +697,7 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
uint32_t ctrl1_irq = 0;
const uint32_t chan_value = LRADC_CH_ACCUMULATE |
((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
- const int len = bitmap_weight(buffer->scan_mask, LRADC_MAX_TOTAL_CHANS);
+ const int len = bitmap_weight(iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS);
if (!len)
return -EINVAL;
@@ -725,7 +724,7 @@ static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
- for_each_set_bit(chan, buffer->scan_mask, LRADC_MAX_TOTAL_CHANS) {
+ for_each_set_bit(chan, iio->active_scan_mask, LRADC_MAX_TOTAL_CHANS) {
ctrl4_set |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
ctrl4_clr |= LRADC_CTRL4_LRADCSELECT_MASK(ofs);
ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs);
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
index d060f25..c99f890 100644
--- a/drivers/staging/iio/light/tsl2x7x_core.c
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -1869,6 +1869,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
dev_info(&chip->client->dev,
"%s: i2c device found does not match expected id\n",
__func__);
+ ret = -EINVAL;
goto fail1;
}
@@ -1907,7 +1908,7 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
if (ret) {
dev_err(&clientp->dev,
"%s: irq request failed", __func__);
- goto fail2;
+ goto fail1;
}
}
@@ -1920,17 +1921,17 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
if (ret) {
dev_err(&clientp->dev,
"%s: iio registration failed\n", __func__);
- goto fail1;
+ goto fail2;
}
dev_info(&clientp->dev, "%s Light sensor found.\n", id->name);
return 0;
-fail1:
+fail2:
if (clientp->irq)
free_irq(clientp->irq, indio_dev);
-fail2:
+fail1:
iio_device_free(indio_dev);
return ret;
diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 8c9e403..ef699f7 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -1,6 +1,7 @@
config DRM_IMX
tristate "DRM Support for Freescale i.MX"
select DRM_KMS_HELPER
+ select VIDEOMODE_HELPERS
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
@@ -19,10 +20,12 @@ config DRM_IMX_FB_HELPER
config DRM_IMX_PARALLEL_DISPLAY
tristate "Support for parallel displays"
depends on DRM_IMX
+ select VIDEOMODE_HELPERS
config DRM_IMX_TVE
tristate "Support for TV and VGA displays"
depends on DRM_IMX
+ select REGMAP_MMIO
help
Choose this to enable the internal Television Encoder (TVe)
found on i.MX53 processors.
@@ -30,6 +33,7 @@ config DRM_IMX_TVE
config DRM_IMX_IPUV3_CORE
tristate "IPUv3 core support"
depends on DRM_IMX
+ depends on RESET_CONTROLLER
help
Choose this if you have a i.MX5/6 system and want
to use the IPU. This option only enables IPU base
@@ -38,5 +42,6 @@ config DRM_IMX_IPUV3_CORE
config DRM_IMX_IPUV3
tristate "DRM Support for i.MX IPUv3"
depends on DRM_IMX
+ depends on DRM_IMX_IPUV3_CORE
help
Choose this if you have a i.MX5 or i.MX6 processor.
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index ac16344..03892de 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -670,7 +670,9 @@ static int imx_tve_probe(struct platform_device *pdev)
tve->dac_reg = devm_regulator_get(&pdev->dev, "dac");
if (!IS_ERR(tve->dac_reg)) {
regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
- regulator_enable(tve->dac_reg);
+ ret = regulator_enable(tve->dac_reg);
+ if (ret)
+ return ret;
}
tve->clk = devm_clk_get(&pdev->dev, "tve");
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index ea61c86..ff5c633 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -316,31 +316,14 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
{
- struct drm_pending_vblank_event *e;
- struct timeval now;
unsigned long flags;
struct drm_device *drm = ipu_crtc->base.dev;
spin_lock_irqsave(&drm->event_lock, flags);
-
- e = ipu_crtc->page_flip_event;
- if (!e) {
- spin_unlock_irqrestore(&drm->event_lock, flags);
- return;
- }
-
- do_gettimeofday(&now);
- e->event.sequence = 0;
- e->event.tv_sec = now.tv_sec;
- e->event.tv_usec = now.tv_usec;
+ if (ipu_crtc->page_flip_event)
+ drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event);
ipu_crtc->page_flip_event = NULL;
-
imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
-
- list_add_tail(&e->base.link, &e->base.file_priv->event_list);
-
- wake_up_interruptible(&e->base.file_priv->event_wait);
-
spin_unlock_irqrestore(&drm->event_lock, flags);
}
diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig
index ec32776..df6569b 100644
--- a/drivers/staging/media/solo6x10/Kconfig
+++ b/drivers/staging/media/solo6x10/Kconfig
@@ -1,6 +1,7 @@
config SOLO6X10
tristate "Softlogic 6x10 MPEG codec cards"
depends on PCI && VIDEO_DEV && SND && I2C
+ depends on FONTS
select VIDEOBUF2_DMA_SG
select VIDEOBUF2_DMA_CONTIG
select SND_PCM
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index a88959f..197c393 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -124,6 +124,20 @@ int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb,
EXPORT_SYMBOL_GPL(nvec_register_notifier);
/**
+ * nvec_unregister_notifier - Unregister a notifier with nvec
+ * @nvec: A &struct nvec_chip
+ * @nb: The notifier block to unregister
+ *
+ * Unregisters a notifier with @nvec. The notifier will be removed from the
+ * atomic notifier chain.
+ */
+int nvec_unregister_notifier(struct nvec_chip *nvec, struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&nvec->notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(nvec_unregister_notifier);
+
+/**
* nvec_status_notifier - The final notifier
*
* Prints a message about control events not handled in the notifier
@@ -185,7 +199,7 @@ static struct nvec_msg *nvec_msg_alloc(struct nvec_chip *nvec,
*
* Free the given message
*/
-inline void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg)
+void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg)
{
if (msg != &nvec->tx_scratch)
dev_vdbg(nvec->dev, "INFO: Free %ti\n", msg - nvec->msg_pool);
@@ -800,11 +814,6 @@ static int tegra_nvec_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -ENODEV;
- }
-
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -815,7 +824,7 @@ static int tegra_nvec_probe(struct platform_device *pdev)
return -ENODEV;
}
- i2c_clk = clk_get(&pdev->dev, "div-clk");
+ i2c_clk = devm_clk_get(&pdev->dev, "div-clk");
if (IS_ERR(i2c_clk)) {
dev_err(nvec->dev, "failed to get controller clock\n");
return -ENODEV;
@@ -902,8 +911,11 @@ static int tegra_nvec_remove(struct platform_device *pdev)
nvec_toggle_global_events(nvec, false);
mfd_remove_devices(nvec->dev);
+ nvec_unregister_notifier(nvec, &nvec->nvec_status_notifier);
cancel_work_sync(&nvec->rx_work);
cancel_work_sync(&nvec->tx_work);
+ /* FIXME: needs check wether nvec is responsible for power off */
+ pm_power_off = NULL;
return 0;
}
diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h
index b7a14bc..2b1316d 100644
--- a/drivers/staging/nvec/nvec.h
+++ b/drivers/staging/nvec/nvec.h
@@ -197,9 +197,8 @@ extern int nvec_register_notifier(struct nvec_chip *nvec,
struct notifier_block *nb,
unsigned int events);
-extern int nvec_unregister_notifier(struct device *dev,
- struct notifier_block *nb,
- unsigned int events);
+extern int nvec_unregister_notifier(struct nvec_chip *dev,
+ struct notifier_block *nb);
extern void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg);
diff --git a/drivers/staging/nvec/nvec_kbd.c b/drivers/staging/nvec/nvec_kbd.c
index 7445ce6..a0ec52a 100644
--- a/drivers/staging/nvec/nvec_kbd.c
+++ b/drivers/staging/nvec/nvec_kbd.c
@@ -169,8 +169,15 @@ fail:
static int nvec_kbd_remove(struct platform_device *pdev)
{
+ struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
+ char disable_kbd[] = { NVEC_KBD, DISABLE_KBD },
+ uncnfg_wake_key_reporting[] = { NVEC_KBD, CNFG_WAKE_KEY_REPORTING,
+ false };
+ nvec_write_async(nvec, uncnfg_wake_key_reporting, 3);
+ nvec_write_async(nvec, disable_kbd, 2);
+ nvec_unregister_notifier(nvec, &keys_dev.notifier);
+
input_unregister_device(keys_dev.input);
- input_free_device(keys_dev.input);
return 0;
}
@@ -188,4 +195,5 @@ module_platform_driver(nvec_kbd_driver);
MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
MODULE_DESCRIPTION("NVEC keyboard driver");
+MODULE_ALIAS("platform:nvec-kbd");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/nvec/nvec_power.c b/drivers/staging/nvec/nvec_power.c
index 296f7b9..aacfcd6 100644
--- a/drivers/staging/nvec/nvec_power.c
+++ b/drivers/staging/nvec/nvec_power.c
@@ -414,6 +414,7 @@ static int nvec_power_remove(struct platform_device *pdev)
struct nvec_power *power = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&power->poller);
+ nvec_unregister_notifier(power->nvec, &power->notifier);
switch (pdev->id) {
case AC:
power_supply_unregister(&nvec_psy);
diff --git a/drivers/staging/nvec/nvec_ps2.c b/drivers/staging/nvec/nvec_ps2.c
index aff6b9b..06dbb02 100644
--- a/drivers/staging/nvec/nvec_ps2.c
+++ b/drivers/staging/nvec/nvec_ps2.c
@@ -106,7 +106,7 @@ static int nvec_mouse_probe(struct platform_device *pdev)
struct serio *ser_dev;
char mouse_reset[] = { NVEC_PS2, SEND_COMMAND, PSMOUSE_RST, 3 };
- ser_dev = devm_kzalloc(&pdev->dev, sizeof(struct serio), GFP_KERNEL);
+ ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (ser_dev == NULL)
return -ENOMEM;
@@ -133,6 +133,11 @@ static int nvec_mouse_probe(struct platform_device *pdev)
static int nvec_mouse_remove(struct platform_device *pdev)
{
+ struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
+
+ ps2_sendcommand(ps2_dev.ser_dev, DISABLE_MOUSE);
+ ps2_stopstreaming(ps2_dev.ser_dev);
+ nvec_unregister_notifier(nvec, &ps2_dev.notifier);
serio_unregister_port(ps2_dev.ser_dev);
return 0;
@@ -179,4 +184,5 @@ module_platform_driver(nvec_mouse_driver);
MODULE_DESCRIPTION("NVEC mouse driver");
MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
+MODULE_ALIAS("platform:nvec-mouse");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 71f5cde..a18430e 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -1271,8 +1271,8 @@ struct sk_buff *DrvAggr_Aggregation(struct net_device *dev, struct ieee80211_drv
/* Subframe drv Tx descriptor and firmware info setting */
skb = pSendList->tx_agg_frames[i];
tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
- tx_agg_desc = (tx_desc_819x_usb_aggr_subframe *)agg_skb->tail;
- tx_fwinfo = (tx_fwinfo_819x_usb *)(agg_skb->tail + sizeof(tx_desc_819x_usb_aggr_subframe));
+ tx_agg_desc = (tx_desc_819x_usb_aggr_subframe *)skb_tail_pointer(agg_skb);
+ tx_fwinfo = (tx_fwinfo_819x_usb *)(skb_tail_pointer(agg_skb) + sizeof(tx_desc_819x_usb_aggr_subframe));
memset(tx_fwinfo,0,sizeof(tx_fwinfo_819x_usb));
/* DWORD 0 */
diff --git a/drivers/staging/sep/Kconfig b/drivers/staging/sep/Kconfig
index 185b676..aab945a 100644
--- a/drivers/staging/sep/Kconfig
+++ b/drivers/staging/sep/Kconfig
@@ -1,6 +1,6 @@
config DX_SEP
tristate "Discretix SEP driver"
- depends on PCI
+ depends on PCI && CRYPTO
help
Discretix SEP driver; used for the security processor subsystem
on board the Intel Mobile Internet Device and adds SEP availability
diff --git a/drivers/staging/silicom/Kconfig b/drivers/staging/silicom/Kconfig
index eda2e7d..6651bd8 100644
--- a/drivers/staging/silicom/Kconfig
+++ b/drivers/staging/silicom/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_SILICOM
bool "Silicom devices"
default y
- depends on PCI
+ depends on PCI && NETDEVICES
---help---
If you have a network card (Ethernet) belonging to this class,
say Y.
@@ -19,7 +19,7 @@ if NET_VENDOR_SILICOM
config SBYPASS
tristate "Silicom BypassCTL library support"
- depends on PCI && NET
+ depends on PCI
depends on m
---help---
If you have a network (Ethernet) controller of this type, say Y
@@ -29,10 +29,9 @@ config SBYPASS
config BPCTL
tristate "Silicom BypassCTL net support"
- depends on PCI && NET
+ depends on PCI
depends on m
select SBYPASS
- select NET_CORE
select MII
---help---
If you have a network (Ethernet) controller of this type, say Y
diff --git a/drivers/staging/silicom/bpctl_mod.c b/drivers/staging/silicom/bpctl_mod.c
index b7e570c..c8ddb99 100644
--- a/drivers/staging/silicom/bpctl_mod.c
+++ b/drivers/staging/silicom/bpctl_mod.c
@@ -133,7 +133,7 @@ static unsigned long str_to_hex(char *p);
static int bp_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
static bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL;
int dev_num = 0, ret = 0, ret_d = 0, time_left = 0;
/* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */
diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
index fe667dd..386362c 100644
--- a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
+++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
@@ -1087,7 +1087,11 @@ static int synaptics_rmi4_resume(struct device *dev)
unsigned char intr_status;
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
- regulator_enable(rmi4_data->regulator);
+ retval = regulator_enable(rmi4_data->regulator);
+ if (retval) {
+ dev_err(dev, "Regulator enable failed (%d)\n", retval);
+ return retval;
+ }
enable_irq(rmi4_data->i2c_client->irq);
rmi4_data->touch_stopped = false;
diff --git a/drivers/staging/vt6656/hostap.c b/drivers/staging/vt6656/hostap.c
index f4f1bf7..c699a30 100644
--- a/drivers/staging/vt6656/hostap.c
+++ b/drivers/staging/vt6656/hostap.c
@@ -133,7 +133,7 @@ static int hostap_disable_hostapd(struct vnt_private *pDevice, int rtnl_locked)
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "%s: Netdevice %s unregistered\n",
pDevice->dev->name, pDevice->apdev->name);
}
- kfree(pDevice->apdev);
+ free_netdev(pDevice->apdev);
pDevice->apdev = NULL;
pDevice->bEnable8021x = false;
pDevice->bEnableHostWEP = false;
diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c
index c335808..d0cf7d8 100644
--- a/drivers/staging/vt6656/iwctl.c
+++ b/drivers/staging/vt6656/iwctl.c
@@ -1345,9 +1345,12 @@ int iwctl_siwpower(struct net_device *dev, struct iw_request_info *info,
return rc;
}
+ spin_lock_irq(&pDevice->lock);
+
if (wrq->disabled) {
pDevice->ePSMode = WMAC_POWER_CAM;
PSvDisablePowerSaving(pDevice);
+ spin_unlock_irq(&pDevice->lock);
return rc;
}
if ((wrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
@@ -1358,6 +1361,9 @@ int iwctl_siwpower(struct net_device *dev, struct iw_request_info *info,
pDevice->ePSMode = WMAC_POWER_FAST;
PSvEnablePowerSaving((void *)pDevice, pMgmt->wListenInterval);
}
+
+ spin_unlock_irq(&pDevice->lock);
+
switch (wrq->flags & IW_POWER_MODE) {
case IW_POWER_UNICAST_R:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " SIOCSIWPOWER: IW_POWER_UNICAST_R \n");
diff --git a/drivers/staging/zcache/ramster.h b/drivers/staging/zcache/ramster.h
index e1f91d5..a858666 100644
--- a/drivers/staging/zcache/ramster.h
+++ b/drivers/staging/zcache/ramster.h
@@ -11,10 +11,6 @@
#ifndef _ZCACHE_RAMSTER_H_
#define _ZCACHE_RAMSTER_H_
-#ifdef CONFIG_RAMSTER_MODULE
-#define CONFIG_RAMSTER
-#endif
-
#ifdef CONFIG_RAMSTER
#include "ramster/ramster.h"
#else
diff --git a/drivers/staging/zcache/ramster/debug.c b/drivers/staging/zcache/ramster/debug.c
index 327e4f0..5b26ee9 100644
--- a/drivers/staging/zcache/ramster/debug.c
+++ b/drivers/staging/zcache/ramster/debug.c
@@ -1,6 +1,8 @@
#include <linux/atomic.h>
#include "debug.h"
+ssize_t ramster_foreign_eph_pages;
+ssize_t ramster_foreign_pers_pages;
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
diff --git a/drivers/staging/zcache/ramster/ramster-howto.txt b/drivers/staging/zcache/ramster/ramster-howto.txt
new file mode 100644
index 0000000..7b1ee3b
--- /dev/null
+++ b/drivers/staging/zcache/ramster/ramster-howto.txt
@@ -0,0 +1,366 @@
+ RAMSTER HOW-TO
+
+Author: Dan Magenheimer
+Ramster maintainer: Konrad Wilk <konrad.wilk@oracle.com>
+
+This is a HOWTO document for ramster which, as of this writing, is in
+the kernel as a subdirectory of zcache in drivers/staging, called ramster.
+(Zcache can be built with or without ramster functionality.) If enabled
+and properly configured, ramster allows memory capacity load balancing
+across multiple machines in a cluster. Further, the ramster code serves
+as an example of asynchronous access for zcache (as well as cleancache and
+frontswap) that may prove useful for future transcendent memory
+implementations, such as KVM and NVRAM. While ramster works today on
+any network connection that supports kernel sockets, its features may
+become more interesting on future high-speed fabrics/interconnects.
+
+Ramster requires both kernel and userland support. The userland support,
+called ramster-tools, is known to work with EL6-based distros, but is a
+set of poorly-hacked slightly-modified cluster tools based on ocfs2, which
+includes an init file, a config file, and a userland binary that interfaces
+to the kernel. This state of userland support reflects the abysmal userland
+skills of this suitably-embarrassed author; any help/patches to turn
+ramster-tools into more distributable rpms/debs useful for a wider range
+of distros would be appreciated. The source RPM that can be used as a
+starting point is available at:
+ http://oss.oracle.com/projects/tmem/files/RAMster/
+
+As a result of this author's ignorance, userland setup described in this
+HOWTO assumes an EL6 distro and is described in EL6 syntax. Apologies
+if this offends anyone!
+
+Kernel support has only been tested on x86_64. Systems with an active
+ocfs2 filesystem should work, but since ramster leverages a lot of
+code from ocfs2, there may be latent issues. A kernel configuration that
+includes CONFIG_OCFS2_FS should build OK, and should certainly run OK
+if no ocfs2 filesystem is mounted.
+
+This HOWTO demonstrates memory capacity load balancing for a two-node
+cluster, where one node called the "local" node becomes overcommitted
+and the other node called the "remote" node provides additional RAM
+capacity for use by the local node. Ramster is capable of more complex
+topologies; see the last section titled "ADVANCED RAMSTER TOPOLOGIES".
+
+If you find any terms in this HOWTO unfamiliar or don't understand the
+motivation for ramster, the following LWN reading is recommended:
+-- Transcendent Memory in a Nutshell (lwn.net/Articles/454795)
+-- The future calculus of memory management (lwn.net/Articles/475681)
+And since ramster is built on top of zcache, this article may be helpful:
+-- In-kernel memory compression (lwn.net/Articles/545244)
+
+Now that you've memorized the contents of those articles, let's get started!
+
+A. PRELIMINARY
+
+1) Install two x86_64 Linux systems that are known to work when
+ upgraded to a recent upstream Linux kernel version.
+
+On each system:
+
+2) Configure, build and install, then boot Linux, just to ensure it
+ can be done with an unmodified upstream kernel. Confirm you booted
+ the upstream kernel with "uname -a".
+
+3) If you plan to do any performance testing or unless you plan to
+ test only swapping, the "WasActive" patch is also highly recommended.
+ (Search lkml.org for WasActive, apply the patch, rebuild your kernel.)
+ For a demo or simple testing, the patch can be ignored.
+
+4) Install ramster-tools as root. An x86_64 rpm for EL6-based systems
+ can be found at:
+ http://oss.oracle.com/projects/tmem/files/RAMster/
+ (Sorry but for now, non-EL6 users must recreate ramster-tools on
+ their own from source. See above.)
+
+5) Ensure that debugfs is mounted at each boot. Examples below assume it
+ is mounted at /sys/kernel/debug.
+
+B. BUILDING RAMSTER INTO THE KERNEL
+
+Do the following on each system:
+
+1) Using the kernel configuration mechanism of your choice, change
+ your config to include:
+
+ CONFIG_CLEANCACHE=y
+ CONFIG_FRONTSWAP=y
+ CONFIG_STAGING=y
+ CONFIG_CONFIGFS_FS=y # NOTE: MUST BE y, not m
+ CONFIG_ZCACHE=y
+ CONFIG_RAMSTER=y
+
+ For a linux-3.10 or later kernel, you should also set:
+
+ CONFIG_ZCACHE_DEBUG=y
+ CONFIG_RAMSTER_DEBUG=y
+
+ Before building the kernel please doublecheck your kernel config
+ file to ensure all of the settings are correct.
+
+2) Build this kernel and change your boot file (e.g. /etc/grub.conf)
+ so that the new kernel will boot.
+
+3) Add "zcache" and "ramster" as kernel boot parameters for the new kernel.
+
+4) Reboot each system approximately simultaneously.
+
+5) Check dmesg to ensure there are some messages from ramster, prefixed
+ by "ramster:"
+
+ # dmesg | grep ramster
+
+ You should also see a lot of files in:
+
+ # ls /sys/kernel/debug/zcache
+ # ls /sys/kernel/debug/ramster
+
+ These are mostly counters for various zcache and ramster activities.
+ You should also see files in:
+
+ # ls /sys/kernel/mm/ramster
+
+ These are sysfs files that control ramster as we shall see.
+
+ Ramster now will act as a single-system zcache on each system
+ but doesn't yet know anything about the cluster so can't yet do
+ anything remotely.
+
+C. CONFIGURING THE RAMSTER CLUSTER
+
+This part can be error prone unless you are familiar with clustering
+filesystems. We need to describe the cluster in a /etc/ramster.conf
+file and the init scripts that parse it are extremely picky about
+the syntax.
+
+1) Create a /etc/ramster.conf file and ensure it is identical on both
+ systems. This file mimics the ocfs2 format and there is a good amount
+ of documentation that can be searched for ocfs2.conf, but you can use:
+
+ cluster:
+ name = ramster
+ node_count = 2
+ node:
+ name = system1
+ cluster = ramster
+ number = 0
+ ip_address = my.ip.ad.r1
+ ip_port = 7777
+ node:
+ name = system2
+ cluster = ramster
+ number = 1
+ ip_address = my.ip.ad.r2
+ ip_port = 7777
+
+ You must ensure that the "name" field in the file exactly matches
+ the output of "hostname" on each system; if "hostname" shows a
+ fully-qualified hostname, ensure the name is fully qualified in
+ /etc/ramster.conf. Obviously, substitute my.ip.ad.rx with proper
+ ip addresses.
+
+2) Enable the ramster service and configure it. If you used the
+ EL6 ramster-tools, this would be:
+
+ # chkconfig --add ramster
+ # service ramster configure
+
+ Set "load on boot" to "y", cluster to start is "ramster" (or whatever
+ name you chose in ramster.conf), heartbeat dead threshold as "500",
+ network idle timeout as "1000000". Leave the others as default.
+
+3) Reboot both systems. After reboot, try (assuming EL6 ramster-tools):
+
+ # service ramster status
+
+ You should see "Checking RAMSTER cluster "ramster": Online". If you do
+ not, something is wrong and ramster will not work. Note that you
+ should also see that the driver for "configfs" is loaded and mounted,
+ the driver for ocfs2_dlmfs is not loaded, and some numbers for network
+ parameters. You will also see "Checking RAMSTER heartbeat: Not active".
+ That's all OK.
+
+4) Now you need to start the cluster heartbeat; the cluster is not "up"
+ until all nodes detect a heartbeat. In a real cluster, heartbeat detection
+ is done via a cluster filesystem, but ramster doesn't require one. Some
+ hack-y kernel code in ramster can start the heartbeat for you though if
+ you tell it what nodes are "up". To enable the heartbeat, do:
+
+ # echo 0 > /sys/kernel/mm/ramster/manual_node_up
+ # echo 1 > /sys/kernel/mm/ramster/manual_node_up
+
+ This must be done on BOTH nodes and, to avoid timeouts, must be done
+ approximately concurrently on both nodes. On an EL6 system, it is
+ convenient to put these lines in /etc/rc.local. To confirm that the
+ cluster is now up, on both systems do:
+
+ # dmesg | grep ramster
+
+ You should see ramster "Accepted connection" messages in dmesg on both
+ nodes after this. Note that if you check userland status again with
+
+ # service ramster status
+
+ you will still see "Checking RAMSTER heartbeat: Not active". That's
+ still OK... the ramster kernel heartbeat hack doesn't communicate to
+ userland.
+
+5) You now must tell each node the node to which it should "remotify" pages.
+ On this two node cluster, we will assume the "local" node, node 0, has
+ memory overcommitted and will use ramster to utilize RAM capacity on
+ the "remote node", node 1. To configure this, on node 0, you do:
+
+ # echo 1 > /sys/kernel/mm/ramster/remote_target_nodenum
+
+ You should see "ramster: node 1 set as remotification target" in dmesg
+ on node 0. Again, on EL6, /etc/rc.local is a good place to put this
+ on node 0 so you don't forget to do it at each boot.
+
+6) One more step: By default, the ramster code does not "remotify" any
+ pages; this is primarily for testing purposes, but sometimes it is
+ useful. This may change in the future, but for now, on node 0, you do:
+
+ # echo 1 > /sys/kernel/mm/ramster/pers_remotify_enable
+ # echo 1 > /sys/kernel/mm/ramster/eph_remotify_enable
+
+ The first enables remotifying swap (persistent, aka frontswap) pages,
+ the second enables remotifying of page cache (ephemeral, cleancache)
+ pages.
+
+ On EL6, these lines can also be put in /etc/rc.local (AFTER the
+ node_up lines), or at the beginning of a script that runs a workload.
+
+7) Note that most testing has been done with both/all machines booted
+ roughly simultaneously to avoid cluster timeouts. Ideally, you should
+ do this too unless you are trying to break ramster rather than just
+ use it. ;-)
+
+D. TESTING RAMSTER
+
+1) Note that ramster has no value unless pages get "remotified". For
+ swap/frontswap/persistent pages, this doesn't happen unless/until
+ the workload would cause swapping to occur, at which point pages
+ are put into frontswap/zcache, and the remotification thread starts
+ working. To get to the point where the system swaps, you either
+ need a workload for which the working set exceeds the RAM in the
+ system; or you need to somehow reduce the amount of RAM one of
+ the system sees. This latter is easy when testing in a VM, but
+ harder on physical systems. In some cases, "mem=xxxM" on the
+ kernel command line restricts memory, but for some values of xxx
+ the kernel may fail to boot. One may also try creating a fixed
+ RAMdisk, doing nothing with it, but ensuring that it eats up a fixed
+ amount of RAM.
+
+2) To see if ramster is working, on the "remote node", node 1, try:
+
+ # grep . /sys/kernel/debug/ramster/foreign_*
+ # # note, that is space-dot-space between grep and the pathname
+
+ to monitor the number (and max) ephemeral and persistent pages
+ that ramster has sent. If these stay at zero, ramster is not working
+ either because the workload on the local node (node 0) isn't creating
+ enough memory pressure or because "remotifying" isn't working. On the
+ local system, node 0, you can watch lots of useful information also.
+ Try:
+
+ grep . /sys/kernel/debug/zcache/*pageframes* \
+ /sys/kernel/debug/zcache/*zbytes* \
+ /sys/kernel/debug/zcache/*zpages* \
+ /sys/kernel/debug/ramster/*remote*
+
+ Of particular note are the remote_*_pages_succ_get counters. These
+ show how many disk reads and/or disk writes have been avoided on the
+ overcommitted local system by storing pages remotely using ramster.
+
+ At the risk of information overload, you can also grep:
+
+ /sys/kernel/debug/cleancache/* and /sys/kernel/debug/frontswap/*
+
+ These show, for example, how many disk reads and/or disk writes have
+ been avoided by using zcache to optimize RAM on the local system.
+
+
+AUTOMATIC SWAP REPATRIATION
+
+You may notice that while the systems are idle, the foreign persistent
+page count on the remote machine slowly decreases. This is because
+ramster implements "frontswap selfshrinking": When possible, swap
+pages that have been remotified are slowly repatriated to the local
+machine. This is so that local RAM can be used when possible and
+so that, in case of remote machine crash, the probability of loss
+of data is reduced.
+
+REBOOTING / POWEROFF
+
+If a system is shut down while some of its swap pages still reside
+on a remote system, the system may lock up during the shutdown
+sequence. This will occur if the network is shut down before the
+swap mechansim is shut down, which is the default ordering on many
+distros. To avoid this annoying problem, simply shut off the swap
+subsystem before starting the shutdown sequence, e.g.:
+
+ # swapoff -a
+ # reboot
+
+Ideally, this swapoff-before-ifdown ordering should be enforced permanently
+using shutdown scripts.
+
+KNOWN PROBLEMS
+
+1) You may periodically see messages such as:
+
+ ramster_r2net, message length problem
+
+ This is harmless but indicates that a node is sending messages
+ containing compressed pages that exceed the maximum for zcache
+ (PAGE_SIZE*15/16). The sender side needs to be fixed.
+
+2) If you see a "No longer connected to node..." message or a "No connection
+ established with node X after N seconds", it is possible you may
+ be in an unrecoverable state. If you are certain all of the
+ appropriate cluster configuration steps described above have been
+ performed, try rebooting the two servers concurrently to see if
+ the cluster starts.
+
+ Note that "Connection to node... shutdown, state 7" is an intermediate
+ connection state. As long as you later see "Accepted connection", the
+ intermediate states are harmless.
+
+3) There are known issues in counting certain values. As a result
+ you may see periodic warnings from the kernel. Almost always you
+ will see "ramster: bad accounting for XXX". There are also "WARN_ONCE"
+ messages. If you see kernel warnings with a tombstone, please report
+ them. They are harmless but reflect bugs that need to be eventually fixed.
+
+ADVANCED RAMSTER TOPOLOGIES
+
+The kernel code for ramster can support up to eight nodes in a cluster,
+but no testing has been done with more than three nodes.
+
+In the example described above, the "remote" node serves as a RAM
+overflow for the "local" node. This can be made symmetric by appropriate
+settings of the sysfs remote_target_nodenum file. For example, by setting:
+
+ # echo 1 > /sys/kernel/mm/ramster/remote_target_nodenum
+
+on node 0, and
+
+ # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
+
+on node 1, each node can serve as a RAM overflow for the other.
+
+For more than two nodes, a "RAM server" can be configured. For a
+three node system, set:
+
+ # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
+
+on node 1, and
+
+ # echo 0 > /sys/kernel/mm/ramster/remote_target_nodenum
+
+on node 2. Then node 0 is a RAM server for node 1 and node 2.
+
+In this implementation of ramster, any remote node is potentially a single
+point of failure (SPOF). Though the probability of failure is reduced
+by automatic swap repatriation (see above), a proposed future enhancement
+to ramster improves high-availability for the cluster by sending a copy
+of each page of date to two other nodes. Patches welcome!
diff --git a/drivers/staging/zcache/ramster/ramster.c b/drivers/staging/zcache/ramster/ramster.c
index b18b887..a937ce1 100644
--- a/drivers/staging/zcache/ramster/ramster.c
+++ b/drivers/staging/zcache/ramster/ramster.c
@@ -66,8 +66,6 @@ static int ramster_remote_target_nodenum __read_mostly = -1;
/* Used by this code. */
long ramster_flnodes;
-ssize_t ramster_foreign_eph_pages;
-ssize_t ramster_foreign_pers_pages;
/* FIXME frontswap selfshrinking knobs in debugfs? */
static LIST_HEAD(ramster_rem_op_list);
@@ -399,14 +397,18 @@ void ramster_count_foreign_pages(bool eph, int count)
inc_ramster_foreign_eph_pages();
} else {
dec_ramster_foreign_eph_pages();
+#ifdef CONFIG_RAMSTER_DEBUG
WARN_ON_ONCE(ramster_foreign_eph_pages < 0);
+#endif
}
} else {
if (count > 0) {
inc_ramster_foreign_pers_pages();
} else {
dec_ramster_foreign_pers_pages();
+#ifdef CONFIG_RAMSTER_DEBUG
WARN_ON_ONCE(ramster_foreign_pers_pages < 0);
+#endif
}
}
}
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index 522cb8e..dcceed2 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -1922,15 +1922,15 @@ out:
#ifdef CONFIG_ZCACHE_MODULE
#ifdef CONFIG_RAMSTER
-module_param(ramster_enabled, int, S_IRUGO);
+module_param(ramster_enabled, bool, S_IRUGO);
module_param(disable_frontswap_selfshrink, int, S_IRUGO);
#endif
-module_param(disable_cleancache, int, S_IRUGO);
-module_param(disable_frontswap, int, S_IRUGO);
+module_param(disable_cleancache, bool, S_IRUGO);
+module_param(disable_frontswap, bool, S_IRUGO);
#ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS
module_param(frontswap_has_exclusive_gets, bool, S_IRUGO);
#endif
-module_param(disable_frontswap_ignore_nonactive, int, S_IRUGO);
+module_param(disable_frontswap_ignore_nonactive, bool, S_IRUGO);
module_param(zcache_comp_name, charp, S_IRUGO);
module_init(zcache_init);
MODULE_LICENSE("GPL");
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index ffbc6a9..d7705e5 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -651,7 +651,7 @@ static int iscsit_add_reject(
cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
if (!cmd->buf_ptr) {
pr_err("Unable to allocate memory for cmd->buf_ptr\n");
- iscsit_release_cmd(cmd);
+ iscsit_free_cmd(cmd, false);
return -1;
}
@@ -697,7 +697,7 @@ int iscsit_add_reject_from_cmd(
cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL);
if (!cmd->buf_ptr) {
pr_err("Unable to allocate memory for cmd->buf_ptr\n");
- iscsit_release_cmd(cmd);
+ iscsit_free_cmd(cmd, false);
return -1;
}
@@ -1250,7 +1250,7 @@ static u32 iscsit_do_crypto_hash_sg(
static void iscsit_do_crypto_hash_buf(
struct hash_desc *hash,
- unsigned char *buf,
+ const void *buf,
u32 payload_length,
u32 padding,
u8 *pad_bytes,
@@ -1743,7 +1743,7 @@ int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
return 0;
out:
if (cmd)
- iscsit_release_cmd(cmd);
+ iscsit_free_cmd(cmd, false);
ping_out:
kfree(ping_data);
return ret;
@@ -2251,7 +2251,7 @@ iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) {
pr_err("Received logout request on connection that"
" is not in logged in state, ignoring request.\n");
- iscsit_release_cmd(cmd);
+ iscsit_free_cmd(cmd, false);
return 0;
}
@@ -2524,9 +2524,8 @@ static int iscsit_send_conn_drop_async_message(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
cmd->tx_size += ISCSI_CRC_LEN;
pr_debug("Attaching CRC32C HeaderDigest to"
@@ -2662,9 +2661,8 @@ static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)cmd->pdu, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->pdu,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
@@ -2841,9 +2839,8 @@ iscsit_send_logout(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)&cmd->pdu[0], ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, &cmd->pdu[0],
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
@@ -2900,9 +2897,8 @@ static int iscsit_send_unsolicited_nopin(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
tx_size += ISCSI_CRC_LEN;
pr_debug("Attaching CRC32C HeaderDigest to"
@@ -2949,9 +2945,8 @@ iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
@@ -3040,9 +3035,8 @@ static int iscsit_send_r2t(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
@@ -3256,9 +3250,8 @@ static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)cmd->pdu, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->pdu,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
@@ -3329,9 +3322,8 @@ iscsit_send_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
@@ -3504,9 +3496,8 @@ static int iscsit_send_text_rsp(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
@@ -3557,11 +3548,11 @@ static int iscsit_send_reject(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn)
{
- u32 iov_count = 0, tx_size = 0;
- struct iscsi_reject *hdr;
+ struct iscsi_reject *hdr = (struct iscsi_reject *)&cmd->pdu[0];
struct kvec *iov;
+ u32 iov_count = 0, tx_size;
- iscsit_build_reject(cmd, conn, (struct iscsi_reject *)&cmd->pdu[0]);
+ iscsit_build_reject(cmd, conn, hdr);
iov = &cmd->iov_misc[0];
iov[iov_count].iov_base = cmd->pdu;
@@ -3574,9 +3565,8 @@ static int iscsit_send_reject(
if (conn->conn_ops->HeaderDigest) {
u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN];
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)hdr, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)header_digest);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, hdr,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)header_digest);
iov[0].iov_len += ISCSI_CRC_LEN;
tx_size += ISCSI_CRC_LEN;
@@ -3585,9 +3575,8 @@ static int iscsit_send_reject(
}
if (conn->conn_ops->DataDigest) {
- iscsit_do_crypto_hash_buf(&conn->conn_tx_hash,
- (unsigned char *)cmd->buf_ptr, ISCSI_HDR_LEN,
- 0, NULL, (u8 *)&cmd->data_crc);
+ iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, cmd->buf_ptr,
+ ISCSI_HDR_LEN, 0, NULL, (u8 *)&cmd->data_crc);
iov[iov_count].iov_base = &cmd->data_crc;
iov[iov_count++].iov_len = ISCSI_CRC_LEN;
@@ -3676,7 +3665,7 @@ iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state
list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
- iscsit_free_cmd(cmd);
+ iscsit_free_cmd(cmd, false);
break;
case ISTATE_SEND_NOPIN_WANT_RESPONSE:
iscsit_mod_nopin_response_timer(conn);
@@ -4133,7 +4122,7 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
iscsit_increment_maxcmdsn(cmd, sess);
- iscsit_free_cmd(cmd);
+ iscsit_free_cmd(cmd, true);
spin_lock_bh(&conn->cmd_lock);
}
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 7816af6..40d9dbc 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -823,7 +823,7 @@ static int iscsit_attach_ooo_cmdsn(
/*
* CmdSN is greater than the tail of the list.
*/
- if (ooo_tail->cmdsn < ooo_cmdsn->cmdsn)
+ if (iscsi_sna_lt(ooo_tail->cmdsn, ooo_cmdsn->cmdsn))
list_add_tail(&ooo_cmdsn->ooo_list,
&sess->sess_ooo_cmdsn_list);
else {
@@ -833,11 +833,12 @@ static int iscsit_attach_ooo_cmdsn(
*/
list_for_each_entry(ooo_tmp, &sess->sess_ooo_cmdsn_list,
ooo_list) {
- if (ooo_tmp->cmdsn < ooo_cmdsn->cmdsn)
+ if (iscsi_sna_lt(ooo_tmp->cmdsn, ooo_cmdsn->cmdsn))
continue;
+ /* Insert before this entry */
list_add(&ooo_cmdsn->ooo_list,
- &ooo_tmp->ooo_list);
+ ooo_tmp->ooo_list.prev);
break;
}
}
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index ba6091b..45a5afd 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -143,7 +143,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
list_del(&cmd->i_conn_node);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
- iscsit_free_cmd(cmd);
+ iscsit_free_cmd(cmd, true);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -165,7 +165,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
list_del(&cmd->i_conn_node);
cmd->conn = NULL;
spin_unlock(&cr->conn_recovery_cmd_lock);
- iscsit_free_cmd(cmd);
+ iscsit_free_cmd(cmd, true);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -248,7 +248,7 @@ void iscsit_discard_cr_cmds_by_expstatsn(
iscsit_remove_cmd_from_connection_recovery(cmd, sess);
spin_unlock(&cr->conn_recovery_cmd_lock);
- iscsit_free_cmd(cmd);
+ iscsit_free_cmd(cmd, true);
spin_lock(&cr->conn_recovery_cmd_lock);
}
spin_unlock(&cr->conn_recovery_cmd_lock);
@@ -302,7 +302,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
- iscsit_free_cmd(cmd);
+ iscsit_free_cmd(cmd, true);
spin_lock_bh(&conn->cmd_lock);
}
spin_unlock_bh(&conn->cmd_lock);
@@ -355,7 +355,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
- iscsit_free_cmd(cmd);
+ iscsit_free_cmd(cmd, true);
spin_lock_bh(&conn->cmd_lock);
continue;
}
@@ -375,7 +375,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
list_del(&cmd->i_conn_node);
spin_unlock_bh(&conn->cmd_lock);
- iscsit_free_cmd(cmd);
+ iscsit_free_cmd(cmd, true);
spin_lock_bh(&conn->cmd_lock);
continue;
}
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index f690be9..e382221 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -436,7 +436,7 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
/*
* Extra parameters for ISER from RFC-5046
*/
- param = iscsi_set_default_param(pl, RDMAEXTENTIONS, INITIAL_RDMAEXTENTIONS,
+ param = iscsi_set_default_param(pl, RDMAEXTENSIONS, INITIAL_RDMAEXTENSIONS,
PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH,
TYPERANGE_BOOL_AND, USE_LEADING_ONLY);
if (!param)
@@ -529,7 +529,7 @@ int iscsi_set_keys_to_negotiate(
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, OFMARKINT)) {
SET_PSTATE_NEGOTIATE(param);
- } else if (!strcmp(param->name, RDMAEXTENTIONS)) {
+ } else if (!strcmp(param->name, RDMAEXTENSIONS)) {
if (iser == true)
SET_PSTATE_NEGOTIATE(param);
} else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) {
@@ -580,7 +580,7 @@ int iscsi_set_keys_irrelevant_for_discovery(
param->state &= ~PSTATE_NEGOTIATE;
else if (!strcmp(param->name, OFMARKINT))
param->state &= ~PSTATE_NEGOTIATE;
- else if (!strcmp(param->name, RDMAEXTENTIONS))
+ else if (!strcmp(param->name, RDMAEXTENSIONS))
param->state &= ~PSTATE_NEGOTIATE;
else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH))
param->state &= ~PSTATE_NEGOTIATE;
@@ -758,9 +758,9 @@ static int iscsi_add_notunderstood_response(
}
INIT_LIST_HEAD(&extra_response->er_list);
- strncpy(extra_response->key, key, strlen(key) + 1);
- strncpy(extra_response->value, NOTUNDERSTOOD,
- strlen(NOTUNDERSTOOD) + 1);
+ strlcpy(extra_response->key, key, sizeof(extra_response->key));
+ strlcpy(extra_response->value, NOTUNDERSTOOD,
+ sizeof(extra_response->value));
list_add_tail(&extra_response->er_list,
&param_list->extra_response_list);
@@ -1629,8 +1629,6 @@ int iscsi_decode_text_input(
if (phase & PHASE_SECURITY) {
if (iscsi_check_for_auth_key(key) > 0) {
- char *tmpptr = key + strlen(key);
- *tmpptr = '=';
kfree(tmpbuf);
return 1;
}
@@ -1977,7 +1975,7 @@ void iscsi_set_session_parameters(
ops->SessionType = !strcmp(param->value, DISCOVERY);
pr_debug("SessionType: %s\n",
param->value);
- } else if (!strcmp(param->name, RDMAEXTENTIONS)) {
+ } else if (!strcmp(param->name, RDMAEXTENSIONS)) {
ops->RDMAExtensions = !strcmp(param->value, YES);
pr_debug("RDMAExtensions: %s\n",
param->value);
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index f31b9c4..a47046a 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -1,8 +1,10 @@
#ifndef ISCSI_PARAMETERS_H
#define ISCSI_PARAMETERS_H
+#include <scsi/iscsi_proto.h>
+
struct iscsi_extra_response {
- char key[64];
+ char key[KEY_MAXLEN];
char value[32];
struct list_head er_list;
} ____cacheline_aligned;
@@ -91,7 +93,7 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
/*
* Parameter names of iSCSI Extentions for RDMA (iSER). See RFC-5046
*/
-#define RDMAEXTENTIONS "RDMAExtensions"
+#define RDMAEXTENSIONS "RDMAExtensions"
#define INITIATORRECVDATASEGMENTLENGTH "InitiatorRecvDataSegmentLength"
#define TARGETRECVDATASEGMENTLENGTH "TargetRecvDataSegmentLength"
@@ -142,7 +144,7 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *,
/*
* Initial values for iSER parameters following RFC-5046 Section 6
*/
-#define INITIAL_RDMAEXTENTIONS NO
+#define INITIAL_RDMAEXTENSIONS NO
#define INITIAL_INITIATORRECVDATASEGMENTLENGTH "262144"
#define INITIAL_TARGETRECVDATASEGMENTLENGTH "8192"
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index 2cc6c9a..08a3bac 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -676,40 +676,56 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
void iscsit_release_cmd(struct iscsi_cmd *cmd)
{
- struct iscsi_conn *conn = cmd->conn;
-
- iscsit_free_r2ts_from_list(cmd);
- iscsit_free_all_datain_reqs(cmd);
-
kfree(cmd->buf_ptr);
kfree(cmd->pdu_list);
kfree(cmd->seq_list);
kfree(cmd->tmr_req);
kfree(cmd->iov_data);
- if (conn) {
+ kmem_cache_free(lio_cmd_cache, cmd);
+}
+
+static void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
+ bool check_queues)
+{
+ struct iscsi_conn *conn = cmd->conn;
+
+ if (scsi_cmd) {
+ if (cmd->data_direction == DMA_TO_DEVICE) {
+ iscsit_stop_dataout_timer(cmd);
+ iscsit_free_r2ts_from_list(cmd);
+ }
+ if (cmd->data_direction == DMA_FROM_DEVICE)
+ iscsit_free_all_datain_reqs(cmd);
+ }
+
+ if (conn && check_queues) {
iscsit_remove_cmd_from_immediate_queue(cmd, conn);
iscsit_remove_cmd_from_response_queue(cmd, conn);
}
-
- kmem_cache_free(lio_cmd_cache, cmd);
}
-void iscsit_free_cmd(struct iscsi_cmd *cmd)
+void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
{
+ struct se_cmd *se_cmd = NULL;
+ int rc;
/*
* Determine if a struct se_cmd is associated with
* this struct iscsi_cmd.
*/
switch (cmd->iscsi_opcode) {
case ISCSI_OP_SCSI_CMD:
- if (cmd->data_direction == DMA_TO_DEVICE)
- iscsit_stop_dataout_timer(cmd);
+ se_cmd = &cmd->se_cmd;
+ __iscsit_free_cmd(cmd, true, shutdown);
/*
* Fallthrough
*/
case ISCSI_OP_SCSI_TMFUNC:
- transport_generic_free_cmd(&cmd->se_cmd, 1);
+ rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
+ if (!rc && shutdown && se_cmd && se_cmd->se_sess) {
+ __iscsit_free_cmd(cmd, true, shutdown);
+ target_put_sess_cmd(se_cmd->se_sess, se_cmd);
+ }
break;
case ISCSI_OP_REJECT:
/*
@@ -718,11 +734,19 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd)
* associated cmd->se_cmd needs to be released.
*/
if (cmd->se_cmd.se_tfo != NULL) {
- transport_generic_free_cmd(&cmd->se_cmd, 1);
+ se_cmd = &cmd->se_cmd;
+ __iscsit_free_cmd(cmd, true, shutdown);
+
+ rc = transport_generic_free_cmd(&cmd->se_cmd, 1);
+ if (!rc && shutdown && se_cmd->se_sess) {
+ __iscsit_free_cmd(cmd, true, shutdown);
+ target_put_sess_cmd(se_cmd->se_sess, se_cmd);
+ }
break;
}
/* Fall-through */
default:
+ __iscsit_free_cmd(cmd, false, shutdown);
cmd->release_cmd(cmd);
break;
}
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index 4f8e01a..a442265 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -29,7 +29,7 @@ extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_co
extern bool iscsit_conn_all_queues_empty(struct iscsi_conn *);
extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *);
extern void iscsit_release_cmd(struct iscsi_cmd *);
-extern void iscsit_free_cmd(struct iscsi_cmd *);
+extern void iscsit_free_cmd(struct iscsi_cmd *, bool);
extern int iscsit_check_session_usage_count(struct iscsi_session *);
extern void iscsit_dec_session_usage_count(struct iscsi_session *);
extern void iscsit_inc_session_usage_count(struct iscsi_session *);
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 43b7ac6..4a8bd36 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -1584,6 +1584,13 @@ static struct target_core_configfs_attribute target_core_attr_dev_udev_path = {
.store = target_core_store_dev_udev_path,
};
+static ssize_t target_core_show_dev_enable(void *p, char *page)
+{
+ struct se_device *dev = p;
+
+ return snprintf(page, PAGE_SIZE, "%d\n", !!(dev->dev_flags & DF_CONFIGURED));
+}
+
static ssize_t target_core_store_dev_enable(
void *p,
const char *page,
@@ -1609,8 +1616,8 @@ static ssize_t target_core_store_dev_enable(
static struct target_core_configfs_attribute target_core_attr_dev_enable = {
.attr = { .ca_owner = THIS_MODULE,
.ca_name = "enable",
- .ca_mode = S_IWUSR },
- .show = NULL,
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = target_core_show_dev_enable,
.store = target_core_store_dev_enable,
};
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index 2e4d655..4630481 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -68,7 +68,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)
struct se_dev_entry *deve = se_cmd->se_deve;
deve->total_cmds++;
- deve->total_bytes += se_cmd->data_length;
if ((se_cmd->data_direction == DMA_TO_DEVICE) &&
(deve->lun_flags & TRANSPORT_LUNFLAGS_READ_ONLY)) {
@@ -85,8 +84,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun)
else if (se_cmd->data_direction == DMA_FROM_DEVICE)
deve->read_bytes += se_cmd->data_length;
- deve->deve_cmds++;
-
se_lun = deve->se_lun;
se_cmd->se_lun = deve->se_lun;
se_cmd->pr_res_key = deve->pr_res_key;
@@ -275,17 +272,6 @@ int core_free_device_list_for_node(
return 0;
}
-void core_dec_lacl_count(struct se_node_acl *se_nacl, struct se_cmd *se_cmd)
-{
- struct se_dev_entry *deve;
- unsigned long flags;
-
- spin_lock_irqsave(&se_nacl->device_list_lock, flags);
- deve = se_nacl->device_list[se_cmd->orig_fe_lun];
- deve->deve_cmds--;
- spin_unlock_irqrestore(&se_nacl->device_list_lock, flags);
-}
-
void core_update_device_list_access(
u32 mapped_lun,
u32 lun_access,
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index 58ed683..b11890d 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -153,10 +153,7 @@ static int fd_configure_device(struct se_device *dev)
struct request_queue *q = bdev_get_queue(inode->i_bdev);
unsigned long long dev_size;
- dev->dev_attrib.hw_block_size =
- bdev_logical_block_size(inode->i_bdev);
- dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q);
-
+ fd_dev->fd_block_size = bdev_logical_block_size(inode->i_bdev);
/*
* Determine the number of bytes from i_size_read() minus
* one (1) logical sector from underlying struct block_device
@@ -203,9 +200,7 @@ static int fd_configure_device(struct se_device *dev)
goto fail;
}
- dev->dev_attrib.hw_block_size = FD_BLOCKSIZE;
- dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS;
-
+ fd_dev->fd_block_size = FD_BLOCKSIZE;
/*
* Limit UNMAP emulation to 8k Number of LBAs (NoLB)
*/
@@ -224,8 +219,8 @@ static int fd_configure_device(struct se_device *dev)
dev->dev_attrib.max_write_same_len = 0x1000;
}
- fd_dev->fd_block_size = dev->dev_attrib.hw_block_size;
-
+ dev->dev_attrib.hw_block_size = fd_dev->fd_block_size;
+ dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS;
dev->dev_attrib.hw_queue_depth = FD_MAX_DEVICE_QUEUE_DEPTH;
if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE) {
@@ -699,11 +694,12 @@ static sector_t fd_get_blocks(struct se_device *dev)
* to handle underlying block_device resize operations.
*/
if (S_ISBLK(i->i_mode))
- dev_size = (i_size_read(i) - fd_dev->fd_block_size);
+ dev_size = i_size_read(i);
else
dev_size = fd_dev->fd_dev_size;
- return div_u64(dev_size, dev->dev_attrib.block_size);
+ return div_u64(dev_size - dev->dev_attrib.block_size,
+ dev->dev_attrib.block_size);
}
static struct sbc_ops fd_sbc_ops = {
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 07f5f94..aa1620a 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -615,6 +615,8 @@ iblock_execute_rw(struct se_cmd *cmd)
rw = WRITE_FUA;
else if (!(q->flush_flags & REQ_FLUSH))
rw = WRITE_FUA;
+ else
+ rw = WRITE;
} else {
rw = WRITE;
}
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 853bab6..18d49df 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -8,7 +8,6 @@ extern struct t10_alua_lu_gp *default_lu_gp;
struct se_dev_entry *core_get_se_deve_from_rtpi(struct se_node_acl *, u16);
int core_free_device_list_for_node(struct se_node_acl *,
struct se_portal_group *);
-void core_dec_lacl_count(struct se_node_acl *, struct se_cmd *);
void core_update_device_list_access(u32, u32, struct se_node_acl *);
int core_enable_device_list_for_node(struct se_lun *, struct se_lun_acl *,
u32, u32, struct se_node_acl *, struct se_portal_group *);
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index e0b3c37..0921a64 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -291,6 +291,11 @@ rd_execute_rw(struct se_cmd *cmd)
u32 src_len;
u64 tmp;
+ if (dev->rd_flags & RDF_NULLIO) {
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
+ return 0;
+ }
+
tmp = cmd->t_task_lba * se_dev->dev_attrib.block_size;
rd_offset = do_div(tmp, PAGE_SIZE);
rd_page = tmp;
@@ -373,11 +378,12 @@ rd_execute_rw(struct se_cmd *cmd)
}
enum {
- Opt_rd_pages, Opt_err
+ Opt_rd_pages, Opt_rd_nullio, Opt_err
};
static match_table_t tokens = {
{Opt_rd_pages, "rd_pages=%d"},
+ {Opt_rd_nullio, "rd_nullio=%d"},
{Opt_err, NULL}
};
@@ -408,6 +414,14 @@ static ssize_t rd_set_configfs_dev_params(struct se_device *dev,
" Count: %u\n", rd_dev->rd_page_count);
rd_dev->rd_flags |= RDF_HAS_PAGE_COUNT;
break;
+ case Opt_rd_nullio:
+ match_int(args, &arg);
+ if (arg != 1)
+ break;
+
+ pr_debug("RAMDISK: Setting NULLIO flag: %d\n", arg);
+ rd_dev->rd_flags |= RDF_NULLIO;
+ break;
default:
break;
}
@@ -424,8 +438,9 @@ static ssize_t rd_show_configfs_dev_params(struct se_device *dev, char *b)
ssize_t bl = sprintf(b, "TCM RamDisk ID: %u RamDisk Makeup: rd_mcp\n",
rd_dev->rd_dev_id);
bl += sprintf(b + bl, " PAGES/PAGE_SIZE: %u*%lu"
- " SG_table_count: %u\n", rd_dev->rd_page_count,
- PAGE_SIZE, rd_dev->sg_table_count);
+ " SG_table_count: %u nullio: %d\n", rd_dev->rd_page_count,
+ PAGE_SIZE, rd_dev->sg_table_count,
+ !!(rd_dev->rd_flags & RDF_NULLIO));
return bl;
}
diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h
index 933b38b..1789d1e 100644
--- a/drivers/target/target_core_rd.h
+++ b/drivers/target/target_core_rd.h
@@ -22,6 +22,7 @@ struct rd_dev_sg_table {
} ____cacheline_aligned;
#define RDF_HAS_PAGE_COUNT 0x01
+#define RDF_NULLIO 0x02
struct rd_dev {
struct se_device dev;
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index f8388b4..21e3158 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -65,7 +65,7 @@ static void transport_complete_task_attr(struct se_cmd *cmd);
static void transport_handle_queue_full(struct se_cmd *cmd,
struct se_device *dev);
static int transport_generic_get_mem(struct se_cmd *cmd);
-static void transport_put_cmd(struct se_cmd *cmd);
+static int transport_put_cmd(struct se_cmd *cmd);
static void target_complete_ok_work(struct work_struct *work);
int init_se_kmem_caches(void)
@@ -221,6 +221,7 @@ struct se_session *transport_init_session(void)
INIT_LIST_HEAD(&se_sess->sess_list);
INIT_LIST_HEAD(&se_sess->sess_acl_list);
INIT_LIST_HEAD(&se_sess->sess_cmd_list);
+ INIT_LIST_HEAD(&se_sess->sess_wait_list);
spin_lock_init(&se_sess->sess_cmd_lock);
kref_init(&se_sess->sess_kref);
@@ -1943,7 +1944,7 @@ static inline void transport_free_pages(struct se_cmd *cmd)
* This routine unconditionally frees a command, and reference counting
* or list removal must be done in the caller.
*/
-static void transport_release_cmd(struct se_cmd *cmd)
+static int transport_release_cmd(struct se_cmd *cmd)
{
BUG_ON(!cmd->se_tfo);
@@ -1955,11 +1956,11 @@ static void transport_release_cmd(struct se_cmd *cmd)
* If this cmd has been setup with target_get_sess_cmd(), drop
* the kref and call ->release_cmd() in kref callback.
*/
- if (cmd->check_release != 0) {
- target_put_sess_cmd(cmd->se_sess, cmd);
- return;
- }
+ if (cmd->check_release != 0)
+ return target_put_sess_cmd(cmd->se_sess, cmd);
+
cmd->se_tfo->release_cmd(cmd);
+ return 1;
}
/**
@@ -1968,7 +1969,7 @@ static void transport_release_cmd(struct se_cmd *cmd)
*
* This routine releases our reference to the command and frees it if possible.
*/
-static void transport_put_cmd(struct se_cmd *cmd)
+static int transport_put_cmd(struct se_cmd *cmd)
{
unsigned long flags;
@@ -1976,7 +1977,7 @@ static void transport_put_cmd(struct se_cmd *cmd)
if (atomic_read(&cmd->t_fe_count) &&
!atomic_dec_and_test(&cmd->t_fe_count)) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
- return;
+ return 0;
}
if (cmd->transport_state & CMD_T_DEV_ACTIVE) {
@@ -1986,8 +1987,7 @@ static void transport_put_cmd(struct se_cmd *cmd)
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
transport_free_pages(cmd);
- transport_release_cmd(cmd);
- return;
+ return transport_release_cmd(cmd);
}
void *transport_kmap_data_sg(struct se_cmd *cmd)
@@ -2152,24 +2152,25 @@ static void transport_write_pending_qf(struct se_cmd *cmd)
}
}
-void transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
+int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
{
+ int ret = 0;
+
if (!(cmd->se_cmd_flags & SCF_SE_LUN_CMD)) {
if (wait_for_tasks && (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB))
transport_wait_for_tasks(cmd);
- transport_release_cmd(cmd);
+ ret = transport_release_cmd(cmd);
} else {
if (wait_for_tasks)
transport_wait_for_tasks(cmd);
- core_dec_lacl_count(cmd->se_sess->se_node_acl, cmd);
-
if (cmd->se_lun)
transport_lun_remove_cmd(cmd);
- transport_put_cmd(cmd);
+ ret = transport_put_cmd(cmd);
}
+ return ret;
}
EXPORT_SYMBOL(transport_generic_free_cmd);
@@ -2213,21 +2214,19 @@ static void target_release_cmd_kref(struct kref *kref)
{
struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
struct se_session *se_sess = se_cmd->se_sess;
- unsigned long flags;
- spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
if (list_empty(&se_cmd->se_cmd_list)) {
- spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+ spin_unlock(&se_sess->sess_cmd_lock);
se_cmd->se_tfo->release_cmd(se_cmd);
return;
}
if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
- spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+ spin_unlock(&se_sess->sess_cmd_lock);
complete(&se_cmd->cmd_wait_comp);
return;
}
list_del(&se_cmd->se_cmd_list);
- spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+ spin_unlock(&se_sess->sess_cmd_lock);
se_cmd->se_tfo->release_cmd(se_cmd);
}
@@ -2238,7 +2237,8 @@ static void target_release_cmd_kref(struct kref *kref)
*/
int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd)
{
- return kref_put(&se_cmd->cmd_kref, target_release_cmd_kref);
+ return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref,
+ &se_sess->sess_cmd_lock);
}
EXPORT_SYMBOL(target_put_sess_cmd);
@@ -2253,11 +2253,14 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
unsigned long flags;
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-
- WARN_ON(se_sess->sess_tearing_down);
+ if (se_sess->sess_tearing_down) {
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+ return;
+ }
se_sess->sess_tearing_down = 1;
+ list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
- list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list)
+ list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
se_cmd->cmd_wait_set = 1;
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
@@ -2266,44 +2269,32 @@ EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
/* target_wait_for_sess_cmds - Wait for outstanding descriptors
* @se_sess: session to wait for active I/O
- * @wait_for_tasks: Make extra transport_wait_for_tasks call
*/
-void target_wait_for_sess_cmds(
- struct se_session *se_sess,
- int wait_for_tasks)
+void target_wait_for_sess_cmds(struct se_session *se_sess)
{
struct se_cmd *se_cmd, *tmp_cmd;
- bool rc = false;
+ unsigned long flags;
list_for_each_entry_safe(se_cmd, tmp_cmd,
- &se_sess->sess_cmd_list, se_cmd_list) {
+ &se_sess->sess_wait_list, se_cmd_list) {
list_del(&se_cmd->se_cmd_list);
pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
" %d\n", se_cmd, se_cmd->t_state,
se_cmd->se_tfo->get_cmd_state(se_cmd));
- if (wait_for_tasks) {
- pr_debug("Calling transport_wait_for_tasks se_cmd: %p t_state: %d,"
- " fabric state: %d\n", se_cmd, se_cmd->t_state,
- se_cmd->se_tfo->get_cmd_state(se_cmd));
-
- rc = transport_wait_for_tasks(se_cmd);
-
- pr_debug("After transport_wait_for_tasks se_cmd: %p t_state: %d,"
- " fabric state: %d\n", se_cmd, se_cmd->t_state,
- se_cmd->se_tfo->get_cmd_state(se_cmd));
- }
-
- if (!rc) {
- wait_for_completion(&se_cmd->cmd_wait_comp);
- pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
- " fabric state: %d\n", se_cmd, se_cmd->t_state,
- se_cmd->se_tfo->get_cmd_state(se_cmd));
- }
+ wait_for_completion(&se_cmd->cmd_wait_comp);
+ pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
+ " fabric state: %d\n", se_cmd, se_cmd->t_state,
+ se_cmd->se_tfo->get_cmd_state(se_cmd));
se_cmd->se_tfo->release_cmd(se_cmd);
}
+
+ spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
+ WARN_ON(!list_empty(&se_sess->sess_cmd_list));
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
}
EXPORT_SYMBOL(target_wait_for_sess_cmds);
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
index 5b4d75f..54ffd64 100644
--- a/drivers/thermal/armada_thermal.c
+++ b/drivers/thermal/armada_thermal.c
@@ -169,21 +169,11 @@ static int armada_thermal_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENODEV;
- }
-
priv->sensor = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->sensor))
return PTR_ERR(priv->sensor);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENODEV;
- }
-
priv->control = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->control))
return PTR_ERR(priv->control);
diff --git a/drivers/thermal/dove_thermal.c b/drivers/thermal/dove_thermal.c
index 4b15a5f..a088d13 100644
--- a/drivers/thermal/dove_thermal.c
+++ b/drivers/thermal/dove_thermal.c
@@ -149,10 +149,6 @@ static int dove_thermal_probe(struct platform_device *pdev)
return PTR_ERR(priv->sensor);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENODEV;
- }
priv->control = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->control))
return PTR_ERR(priv->control);
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
index d20ce9e..788b1dd 100644
--- a/drivers/thermal/exynos_thermal.c
+++ b/drivers/thermal/exynos_thermal.c
@@ -925,11 +925,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
INIT_WORK(&data->irq_work, exynos_tmu_work);
data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!data->mem) {
- dev_err(&pdev->dev, "Failed to get platform resource\n");
- return -ENOENT;
- }
-
data->base = devm_ioremap_resource(&pdev->dev, data->mem);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 6d0c27c..9bffcec 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -859,6 +859,7 @@ error:
*/
static void __exit ehv_bc_exit(void)
{
+ platform_driver_unregister(&ehv_bc_tty_driver);
tty_unregister_driver(ehv_bc_driver);
put_tty_driver(ehv_bc_driver);
kfree(bcs);
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 71d6eb2..4c4a236 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -1618,8 +1618,12 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
if (ip->type == PORT_16550A)
me->fifo[p] = 1;
- opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
- opmode &= OP_MODE_MASK;
+ if (ip->board->chip_flag == MOXA_MUST_MU860_HWID) {
+ opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
+ opmode &= OP_MODE_MASK;
+ } else {
+ opmode = RS232_MODE;
+ }
me->iftype[p] = opmode;
mutex_unlock(&port->mutex);
}
@@ -1676,6 +1680,9 @@ static int mxser_ioctl(struct tty_struct *tty,
int shiftbit;
unsigned char val, mask;
+ if (info->board->chip_flag != MOXA_MUST_MU860_HWID)
+ return -EFAULT;
+
p = tty->index % 4;
if (cmd == MOXA_SET_OP_MODE) {
if (get_user(opmode, (int __user *) argp))
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index d655416..6c7fe90 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1573,6 +1573,14 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
ldata->real_raw = 0;
}
n_tty_set_room(tty);
+ /*
+ * Fix tty hang when I_IXON(tty) is cleared, but the tty
+ * been stopped by STOP_CHAR(tty) before it.
+ */
+ if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
+ start_tty(tty);
+ }
+
/* The termios change make the tty ready for I/O */
wake_up_interruptible(&tty->write_wait);
wake_up_interruptible(&tty->read_wait);
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 82d35c5..354564e 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -150,12 +150,14 @@ static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
AIOP_INTR_BIT_3
};
+#ifdef CONFIG_PCI
static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
UPCI_AIOP_INTR_BIT_0,
UPCI_AIOP_INTR_BIT_1,
UPCI_AIOP_INTR_BIT_2,
UPCI_AIOP_INTR_BIT_3
};
+#endif
static Byte_t RData[RDATASIZE] = {
0x00, 0x09, 0xf6, 0x82,
@@ -227,7 +229,6 @@ static unsigned long nextLineNumber;
static int __init init_ISA(int i);
static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
static void rp_flush_buffer(struct tty_struct *tty);
-static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
static void rp_start(struct tty_struct *tty);
@@ -241,11 +242,6 @@ static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
-static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
- ByteIO_t * AiopIOList, int AiopIOListSize,
- WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
- int PeriodicOnly, int altChanRingIndicator,
- int UPCIRingInd);
static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
ByteIO_t * AiopIOList, int AiopIOListSize,
int IRQNum, Byte_t Frequency, int PeriodicOnly);
@@ -1775,6 +1771,145 @@ static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = {
};
MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
+/* Resets the speaker controller on RocketModem II and III devices */
+static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
+{
+ ByteIO_t addr;
+
+ /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
+ if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
+ addr = CtlP->AiopIO[0] + 0x4F;
+ sOutB(addr, 0);
+ }
+
+ /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
+ if ((model == MODEL_UPCI_RM3_8PORT)
+ || (model == MODEL_UPCI_RM3_4PORT)) {
+ addr = CtlP->AiopIO[0] + 0x88;
+ sOutB(addr, 0);
+ }
+}
+
+/***************************************************************************
+Function: sPCIInitController
+Purpose: Initialization of controller global registers and controller
+ structure.
+Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
+ IRQNum,Frequency,PeriodicOnly)
+ CONTROLLER_T *CtlP; Ptr to controller structure
+ int CtlNum; Controller number
+ ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
+ This list must be in the order the AIOPs will be found on the
+ controller. Once an AIOP in the list is not found, it is
+ assumed that there are no more AIOPs on the controller.
+ int AiopIOListSize; Number of addresses in AiopIOList
+ int IRQNum; Interrupt Request number. Can be any of the following:
+ 0: Disable global interrupts
+ 3: IRQ 3
+ 4: IRQ 4
+ 5: IRQ 5
+ 9: IRQ 9
+ 10: IRQ 10
+ 11: IRQ 11
+ 12: IRQ 12
+ 15: IRQ 15
+ Byte_t Frequency: A flag identifying the frequency
+ of the periodic interrupt, can be any one of the following:
+ FREQ_DIS - periodic interrupt disabled
+ FREQ_137HZ - 137 Hertz
+ FREQ_69HZ - 69 Hertz
+ FREQ_34HZ - 34 Hertz
+ FREQ_17HZ - 17 Hertz
+ FREQ_9HZ - 9 Hertz
+ FREQ_4HZ - 4 Hertz
+ If IRQNum is set to 0 the Frequency parameter is
+ overidden, it is forced to a value of FREQ_DIS.
+ int PeriodicOnly: 1 if all interrupts except the periodic
+ interrupt are to be blocked.
+ 0 is both the periodic interrupt and
+ other channel interrupts are allowed.
+ If IRQNum is set to 0 the PeriodicOnly parameter is
+ overidden, it is forced to a value of 0.
+Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
+ initialization failed.
+
+Comments:
+ If periodic interrupts are to be disabled but AIOP interrupts
+ are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
+
+ If interrupts are to be completely disabled set IRQNum to 0.
+
+ Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
+ invalid combination.
+
+ This function performs initialization of global interrupt modes,
+ but it does not actually enable global interrupts. To enable
+ and disable global interrupts use functions sEnGlobalInt() and
+ sDisGlobalInt(). Enabling of global interrupts is normally not
+ done until all other initializations are complete.
+
+ Even if interrupts are globally enabled, they must also be
+ individually enabled for each channel that is to generate
+ interrupts.
+
+Warnings: No range checking on any of the parameters is done.
+
+ No context switches are allowed while executing this function.
+
+ After this function all AIOPs on the controller are disabled,
+ they can be enabled with sEnAiop().
+*/
+static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
+ int PeriodicOnly, int altChanRingIndicator,
+ int UPCIRingInd)
+{
+ int i;
+ ByteIO_t io;
+
+ CtlP->AltChanRingIndicator = altChanRingIndicator;
+ CtlP->UPCIRingInd = UPCIRingInd;
+ CtlP->CtlNum = CtlNum;
+ CtlP->CtlID = CTLID_0001; /* controller release 1 */
+ CtlP->BusType = isPCI; /* controller release 1 */
+
+ if (ConfigIO) {
+ CtlP->isUPCI = 1;
+ CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
+ CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
+ CtlP->AiopIntrBits = upci_aiop_intr_bits;
+ } else {
+ CtlP->isUPCI = 0;
+ CtlP->PCIIO =
+ (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
+ CtlP->AiopIntrBits = aiop_intr_bits;
+ }
+
+ sPCIControllerEOI(CtlP); /* clear EOI if warm init */
+ /* Init AIOPs */
+ CtlP->NumAiop = 0;
+ for (i = 0; i < AiopIOListSize; i++) {
+ io = AiopIOList[i];
+ CtlP->AiopIO[i] = (WordIO_t) io;
+ CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
+
+ CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
+ if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
+ break; /* done looking for AIOPs */
+
+ CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
+ sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
+ sOutB(io + _INDX_DATA, sClockPrescale);
+ CtlP->NumAiop++; /* bump count of AIOPs */
+ }
+
+ if (CtlP->NumAiop == 0)
+ return (-1);
+ else
+ return (CtlP->NumAiop);
+}
+
/*
* Called when a PCI card is found. Retrieves and stores model information,
* init's aiopic and serial port hardware.
@@ -2519,147 +2654,6 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
return (CtlP->NumAiop);
}
-#ifdef CONFIG_PCI
-/***************************************************************************
-Function: sPCIInitController
-Purpose: Initialization of controller global registers and controller
- structure.
-Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
- IRQNum,Frequency,PeriodicOnly)
- CONTROLLER_T *CtlP; Ptr to controller structure
- int CtlNum; Controller number
- ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
- This list must be in the order the AIOPs will be found on the
- controller. Once an AIOP in the list is not found, it is
- assumed that there are no more AIOPs on the controller.
- int AiopIOListSize; Number of addresses in AiopIOList
- int IRQNum; Interrupt Request number. Can be any of the following:
- 0: Disable global interrupts
- 3: IRQ 3
- 4: IRQ 4
- 5: IRQ 5
- 9: IRQ 9
- 10: IRQ 10
- 11: IRQ 11
- 12: IRQ 12
- 15: IRQ 15
- Byte_t Frequency: A flag identifying the frequency
- of the periodic interrupt, can be any one of the following:
- FREQ_DIS - periodic interrupt disabled
- FREQ_137HZ - 137 Hertz
- FREQ_69HZ - 69 Hertz
- FREQ_34HZ - 34 Hertz
- FREQ_17HZ - 17 Hertz
- FREQ_9HZ - 9 Hertz
- FREQ_4HZ - 4 Hertz
- If IRQNum is set to 0 the Frequency parameter is
- overidden, it is forced to a value of FREQ_DIS.
- int PeriodicOnly: 1 if all interrupts except the periodic
- interrupt are to be blocked.
- 0 is both the periodic interrupt and
- other channel interrupts are allowed.
- If IRQNum is set to 0 the PeriodicOnly parameter is
- overidden, it is forced to a value of 0.
-Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
- initialization failed.
-
-Comments:
- If periodic interrupts are to be disabled but AIOP interrupts
- are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
-
- If interrupts are to be completely disabled set IRQNum to 0.
-
- Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
- invalid combination.
-
- This function performs initialization of global interrupt modes,
- but it does not actually enable global interrupts. To enable
- and disable global interrupts use functions sEnGlobalInt() and
- sDisGlobalInt(). Enabling of global interrupts is normally not
- done until all other initializations are complete.
-
- Even if interrupts are globally enabled, they must also be
- individually enabled for each channel that is to generate
- interrupts.
-
-Warnings: No range checking on any of the parameters is done.
-
- No context switches are allowed while executing this function.
-
- After this function all AIOPs on the controller are disabled,
- they can be enabled with sEnAiop().
-*/
-static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
- ByteIO_t * AiopIOList, int AiopIOListSize,
- WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
- int PeriodicOnly, int altChanRingIndicator,
- int UPCIRingInd)
-{
- int i;
- ByteIO_t io;
-
- CtlP->AltChanRingIndicator = altChanRingIndicator;
- CtlP->UPCIRingInd = UPCIRingInd;
- CtlP->CtlNum = CtlNum;
- CtlP->CtlID = CTLID_0001; /* controller release 1 */
- CtlP->BusType = isPCI; /* controller release 1 */
-
- if (ConfigIO) {
- CtlP->isUPCI = 1;
- CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
- CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
- CtlP->AiopIntrBits = upci_aiop_intr_bits;
- } else {
- CtlP->isUPCI = 0;
- CtlP->PCIIO =
- (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
- CtlP->AiopIntrBits = aiop_intr_bits;
- }
-
- sPCIControllerEOI(CtlP); /* clear EOI if warm init */
- /* Init AIOPs */
- CtlP->NumAiop = 0;
- for (i = 0; i < AiopIOListSize; i++) {
- io = AiopIOList[i];
- CtlP->AiopIO[i] = (WordIO_t) io;
- CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
-
- CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
- if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
- break; /* done looking for AIOPs */
-
- CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
- sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
- sOutB(io + _INDX_DATA, sClockPrescale);
- CtlP->NumAiop++; /* bump count of AIOPs */
- }
-
- if (CtlP->NumAiop == 0)
- return (-1);
- else
- return (CtlP->NumAiop);
-}
-
-/* Resets the speaker controller on RocketModem II and III devices */
-static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
-{
- ByteIO_t addr;
-
- /* RocketModem II speaker control is at the 8th port location of offset 0x40 */
- if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
- addr = CtlP->AiopIO[0] + 0x4F;
- sOutB(addr, 0);
- }
-
- /* RocketModem III speaker control is at the 1st port location of offset 0x80 */
- if ((model == MODEL_UPCI_RM3_8PORT)
- || (model == MODEL_UPCI_RM3_4PORT)) {
- addr = CtlP->AiopIO[0] + 0x88;
- sOutB(addr, 0);
- }
-}
-#endif
-
/***************************************************************************
Function: sReadAiopID
Purpose: Read the AIOP idenfication number directly from an AIOP.
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 46528d5..86c00b1 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -2755,7 +2755,7 @@ static void __init serial8250_isa_init_ports(void)
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
- for (i = 0; i < UART_NR; i++) {
+ for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
struct uart_port *port = &up->port;
@@ -2916,7 +2916,7 @@ static int __init serial8250_console_setup(struct console *co, char *options)
* if so, search for the first available port that does have
* console support.
*/
- if (co->index >= UART_NR)
+ if (co->index >= nr_uarts)
co->index = 0;
port = &serial8250_ports[co->index].port;
if (!port->iobase && !port->membase)
@@ -2957,7 +2957,7 @@ int serial8250_find_port(struct uart_port *p)
int line;
struct uart_port *port;
- for (line = 0; line < UART_NR; line++) {
+ for (line = 0; line < nr_uarts; line++) {
port = &serial8250_ports[line].port;
if (uart_match_port(p, port))
return line;
@@ -3110,7 +3110,7 @@ static int serial8250_remove(struct platform_device *dev)
{
int i;
- for (i = 0; i < UART_NR; i++) {
+ for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev == &dev->dev)
@@ -3178,7 +3178,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
/*
* First, find a port entry which matches.
*/
- for (i = 0; i < UART_NR; i++)
+ for (i = 0; i < nr_uarts; i++)
if (uart_match_port(&serial8250_ports[i].port, port))
return &serial8250_ports[i];
@@ -3187,7 +3187,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
* free entry. We look for one which hasn't been previously
* used (indicated by zero iobase).
*/
- for (i = 0; i < UART_NR; i++)
+ for (i = 0; i < nr_uarts; i++)
if (serial8250_ports[i].port.type == PORT_UNKNOWN &&
serial8250_ports[i].port.iobase == 0)
return &serial8250_ports[i];
@@ -3196,7 +3196,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
* That also failed. Last resort is to find any entry which
* doesn't have a real port associated with it.
*/
- for (i = 0; i < UART_NR; i++)
+ for (i = 0; i < nr_uarts; i++)
if (serial8250_ports[i].port.type == PORT_UNKNOWN)
return &serial8250_ports[i];
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index beaa283..d07b6af 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -338,7 +338,8 @@ static int dw8250_runtime_suspend(struct device *dev)
{
struct dw8250_data *data = dev_get_drvdata(dev);
- clk_disable_unprepare(data->clk);
+ if (!IS_ERR(data->clk))
+ clk_disable_unprepare(data->clk);
return 0;
}
@@ -347,7 +348,8 @@ static int dw8250_runtime_resume(struct device *dev)
{
struct dw8250_data *data = dev_get_drvdata(dev);
- clk_prepare_enable(data->clk);
+ if (!IS_ERR(data->clk))
+ clk_prepare_enable(data->clk);
return 0;
}
@@ -367,6 +369,7 @@ MODULE_DEVICE_TABLE(of, dw8250_of_match);
static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT33C4", 0 },
{ "INT33C5", 0 },
+ { "80860F0A", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8ab70a6..e2774f9 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -332,7 +332,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *
dmaengine_slave_config(chan, &rx_conf);
uap->dmarx.chan = chan;
- if (plat->dma_rx_poll_enable) {
+ if (plat && plat->dma_rx_poll_enable) {
/* Set poll rate if specified. */
if (plat->dma_rx_poll_rate) {
uap->dmarx.auto_poll_rate = false;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 147c9e1..8cdfbd3 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -761,6 +761,8 @@ static int imx_startup(struct uart_port *port)
temp = readl(sport->port.membase + UCR2);
temp |= (UCR2_RXEN | UCR2_TXEN);
+ if (!sport->have_rtscts)
+ temp |= UCR2_IRTS;
writel(temp, sport->port.membase + UCR2);
if (USE_IRDA(sport)) {
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index e956377..65be0c0 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -707,8 +707,10 @@ static int __init mcf_init(void)
if (rc)
return rc;
rc = platform_driver_register(&mcf_platform_driver);
- if (rc)
+ if (rc) {
+ uart_unregister_driver(&mcf_driver);
return rc;
+ }
return 0;
}
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 018bad9..f51b280 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1497,18 +1497,23 @@ mpc52xx_uart_init(void)
if (psc_ops && psc_ops->fifoc_init) {
ret = psc_ops->fifoc_init();
if (ret)
- return ret;
+ goto err_init;
}
ret = platform_driver_register(&mpc52xx_uart_of_driver);
if (ret) {
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
__FILE__, ret);
- uart_unregister_driver(&mpc52xx_uart_driver);
- return ret;
+ goto err_reg;
}
return 0;
+err_reg:
+ if (psc_ops && psc_ops->fifoc_uninit)
+ psc_ops->fifoc_uninit();
+err_init:
+ uart_unregister_driver(&mpc52xx_uart_driver);
+ return ret;
}
static void __exit
diff --git a/drivers/tty/serial/nwpserial.c b/drivers/tty/serial/nwpserial.c
index 77287c5..549c70a2 100644
--- a/drivers/tty/serial/nwpserial.c
+++ b/drivers/tty/serial/nwpserial.c
@@ -199,7 +199,7 @@ static void nwpserial_shutdown(struct uart_port *port)
dcr_write(up->dcr_host, UART_IER, up->ier);
/* free irq */
- free_irq(up->port.irq, port);
+ free_irq(up->port.irq, up);
}
static int nwpserial_verify_port(struct uart_port *port,
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 30d4f7a..f0b9f6b 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -202,26 +202,6 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
return pdata->get_context_loss_count(up->dev);
}
-static void serial_omap_set_forceidle(struct uart_omap_port *up)
-{
- struct omap_uart_port_info *pdata = up->dev->platform_data;
-
- if (!pdata || !pdata->set_forceidle)
- return;
-
- pdata->set_forceidle(up->dev);
-}
-
-static void serial_omap_set_noidle(struct uart_omap_port *up)
-{
- struct omap_uart_port_info *pdata = up->dev->platform_data;
-
- if (!pdata || !pdata->set_noidle)
- return;
-
- pdata->set_noidle(up->dev);
-}
-
static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
{
struct omap_uart_port_info *pdata = up->dev->platform_data;
@@ -298,8 +278,6 @@ static void serial_omap_stop_tx(struct uart_port *port)
serial_out(up, UART_IER, up->ier);
}
- serial_omap_set_forceidle(up);
-
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
}
@@ -364,7 +342,6 @@ static void serial_omap_start_tx(struct uart_port *port)
pm_runtime_get_sync(up->dev);
serial_omap_enable_ier_thri(up);
- serial_omap_set_noidle(up);
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
}
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 074b919..0c8a9fa 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1166,6 +1166,18 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
ourport->tx_irq = ret;
ourport->clk = clk_get(&platdev->dev, "uart");
+ if (IS_ERR(ourport->clk)) {
+ pr_err("%s: Controller clock not found\n",
+ dev_name(&platdev->dev));
+ return PTR_ERR(ourport->clk);
+ }
+
+ ret = clk_prepare_enable(ourport->clk);
+ if (ret) {
+ pr_err("uart: clock failed to prepare+enable: %d\n", ret);
+ clk_put(ourport->clk);
+ return ret;
+ }
/* Keep all interrupts masked and cleared */
if (s3c24xx_serial_has_interrupt_mask(port)) {
@@ -1180,6 +1192,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
/* reset the fifos (and setup the uart) */
s3c24xx_serial_resetport(port, cfg);
+ clk_disable_unprepare(ourport->clk);
return 0;
}
@@ -1803,6 +1816,7 @@ static int __init s3c24xx_serial_modinit(void)
static void __exit s3c24xx_serial_modexit(void)
{
+ platform_driver_unregister(&samsung_serial_driver);
uart_unregister_driver(&s3c24xx_uart_drv);
}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index fbd447b..740202d 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -779,7 +779,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
con_set_default_unimap(vc);
vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) {
- tty_port_destroy(&vc->port);
kfree(vc);
vc_cons[currcons].d = NULL;
return -ENOMEM;
@@ -986,26 +985,25 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws)
return ret;
}
-void vc_deallocate(unsigned int currcons)
+struct vc_data *vc_deallocate(unsigned int currcons)
{
+ struct vc_data *vc = NULL;
+
WARN_CONSOLE_UNLOCKED();
if (vc_cons_allocated(currcons)) {
- struct vc_data *vc = vc_cons[currcons].d;
- struct vt_notifier_param param = { .vc = vc };
+ struct vt_notifier_param param;
+ param.vc = vc = vc_cons[currcons].d;
atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
vcs_remove_sysfs(currcons);
vc->vc_sw->con_deinit(vc);
put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner);
kfree(vc->vc_screenbuf);
- if (currcons >= MIN_NR_CONSOLES) {
- tty_port_destroy(&vc->port);
- kfree(vc);
- }
vc_cons[currcons].d = NULL;
}
+ return vc;
}
/*
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index 98ff173..fc2c06c 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -283,6 +283,51 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
return 0;
}
+/* deallocate a single console, if possible (leave 0) */
+static int vt_disallocate(unsigned int vc_num)
+{
+ struct vc_data *vc = NULL;
+ int ret = 0;
+
+ if (!vc_num)
+ return 0;
+
+ console_lock();
+ if (VT_BUSY(vc_num))
+ ret = -EBUSY;
+ else
+ vc = vc_deallocate(vc_num);
+ console_unlock();
+
+ if (vc && vc_num >= MIN_NR_CONSOLES) {
+ tty_port_destroy(&vc->port);
+ kfree(vc);
+ }
+
+ return ret;
+}
+
+/* deallocate all unused consoles, but leave 0 */
+static void vt_disallocate_all(void)
+{
+ struct vc_data *vc[MAX_NR_CONSOLES];
+ int i;
+
+ console_lock();
+ for (i = 1; i < MAX_NR_CONSOLES; i++)
+ if (!VT_BUSY(i))
+ vc[i] = vc_deallocate(i);
+ else
+ vc[i] = NULL;
+ console_unlock();
+
+ for (i = 1; i < MAX_NR_CONSOLES; i++) {
+ if (vc[i] && i >= MIN_NR_CONSOLES) {
+ tty_port_destroy(&vc[i]->port);
+ kfree(vc[i]);
+ }
+ }
+}
/*
@@ -769,24 +814,10 @@ int vt_ioctl(struct tty_struct *tty,
ret = -ENXIO;
break;
}
- if (arg == 0) {
- /* deallocate all unused consoles, but leave 0 */
- console_lock();
- for (i=1; i<MAX_NR_CONSOLES; i++)
- if (! VT_BUSY(i))
- vc_deallocate(i);
- console_unlock();
- } else {
- /* deallocate a single console, if possible */
- arg--;
- if (VT_BUSY(arg))
- ret = -EBUSY;
- else if (arg) { /* leave 0 */
- console_lock();
- vc_deallocate(arg);
- console_unlock();
- }
- }
+ if (arg == 0)
+ vt_disallocate_all();
+ else
+ ret = vt_disallocate(--arg);
break;
case VT_RESIZE:
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index e92eeaf..5295be0 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -45,6 +45,7 @@ config UIO_PDRV_GENIRQ
config UIO_DMEM_GENIRQ
tristate "Userspace platform driver with generic irq and dynamic memory"
+ depends on HAS_DMA
help
Platform driver for Userspace I/O devices, including generic
interrupt handling code. Shared interrupts are not supported.
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index b7eb86a..8a7eb77 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -686,7 +686,8 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
{
int ret, len;
__le32 *buf;
- int offb, offd;
+ int offb;
+ unsigned int offd;
const int stride = CMD_PACKET_SIZE / (4 * 2) - 1;
int buflen = ((size - 1) / stride + 1 + size * 2) * 4;
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
index 608a2ae..b2df442 100644
--- a/drivers/usb/chipidea/Kconfig
+++ b/drivers/usb/chipidea/Kconfig
@@ -20,7 +20,7 @@ config USB_CHIPIDEA_UDC
config USB_CHIPIDEA_HOST
bool "ChipIdea host controller"
depends on USB=y || USB=USB_CHIPIDEA
- depends on USB_EHCI_HCD
+ depends on USB_EHCI_HCD=y
select USB_EHCI_ROOT_HUB_TT
help
Say Y here to enable host controller functionality of the
diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
index 8faec9d..73f9d5f 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci13xxx_imx.c
@@ -173,17 +173,10 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
ci13xxx_imx_platdata.phy = data->phy;
- if (!pdev->dev.dma_mask) {
- pdev->dev.dma_mask = devm_kzalloc(&pdev->dev,
- sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
- if (!pdev->dev.dma_mask) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "Failed to alloc dma_mask!\n");
- goto err;
- }
- *pdev->dev.dma_mask = DMA_BIT_MASK(32);
- dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask);
- }
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
if (usbmisc_ops && usbmisc_ops->init) {
ret = usbmisc_ops->init(&pdev->dev);
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 450107e..475c9c1 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -276,8 +276,9 @@ static void ci_role_work(struct work_struct *work)
ci_role_stop(ci);
ci_role_start(ci, role);
- enable_irq(ci->irq);
}
+
+ enable_irq(ci->irq);
}
static irqreturn_t ci_irq(int irq, void *data)
@@ -370,11 +371,6 @@ static int ci_hdrc_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "missing resource\n");
- return -ENODEV;
- }
-
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 519ead2..b501346 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1678,8 +1678,11 @@ static int udc_start(struct ci13xxx *ci)
ci->gadget.ep0 = &ci->ep0in->ep;
- if (ci->global_phy)
+ if (ci->global_phy) {
ci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR(ci->transceiver))
+ ci->transceiver = NULL;
+ }
if (ci->platdata->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
if (ci->transceiver == NULL) {
@@ -1694,7 +1697,7 @@ static int udc_start(struct ci13xxx *ci)
goto put_transceiver;
}
- if (!IS_ERR_OR_NULL(ci->transceiver)) {
+ if (ci->transceiver) {
retval = otg_set_peripheral(ci->transceiver->otg,
&ci->gadget);
if (retval)
@@ -1711,7 +1714,7 @@ static int udc_start(struct ci13xxx *ci)
return retval;
remove_trans:
- if (!IS_ERR_OR_NULL(ci->transceiver)) {
+ if (ci->transceiver) {
otg_set_peripheral(ci->transceiver->otg, NULL);
if (ci->global_phy)
usb_put_phy(ci->transceiver);
@@ -1719,7 +1722,7 @@ remove_trans:
dev_err(dev, "error = %i\n", retval);
put_transceiver:
- if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)
+ if (ci->transceiver && ci->global_phy)
usb_put_phy(ci->transceiver);
destroy_eps:
destroy_eps(ci);
@@ -1747,7 +1750,7 @@ static void udc_stop(struct ci13xxx *ci)
dma_pool_destroy(ci->td_pool);
dma_pool_destroy(ci->qh_pool);
- if (!IS_ERR_OR_NULL(ci->transceiver)) {
+ if (ci->transceiver) {
otg_set_peripheral(ci->transceiver->otg, NULL);
if (ci->global_phy)
usb_put_phy(ci->transceiver);
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 8772b36..db535b0 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -51,7 +51,7 @@ config USB_DYNAMIC_MINORS
config USB_OTG
bool "OTG support"
- depends on USB_SUSPEND
+ depends on PM_RUNTIME
default n
help
The most notable feature of USB OTG is support for a
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index caefc80..c88c4fb 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1287,9 +1287,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
goto error;
}
for (totlen = u = 0; u < uurb->number_of_packets; u++) {
- /* arbitrary limit,
- * sufficient for USB 2.0 high-bandwidth iso */
- if (isopkt[u].length > 8192) {
+ /*
+ * arbitrary limit need for USB 3.0
+ * bMaxBurst (0~15 allowed, 1~16 packets)
+ * bmAttributes (bit 1:0, mult 0~2, 1~3 packets)
+ * sizemax: 1024 * 16 * 3 = 49152
+ */
+ if (isopkt[u].length > 49152) {
ret = -EINVAL;
goto error;
}
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index ab5638d..a635988 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -88,6 +88,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Edirol SD-20 */
{ USB_DEVICE(0x0582, 0x0027), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Alcor Micro Corp. Hub */
+ { USB_DEVICE(0x058f, 0x9254), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* appletouch */
{ USB_DEVICE(0x05ac, 0x021a), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index ea5ee9c..757aa18 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -19,21 +19,21 @@ choice
config USB_DWC3_HOST
bool "Host only mode"
- depends on USB
+ depends on USB=y || USB=USB_DWC3
help
Select this when you want to use DWC3 in host mode only,
thereby the gadget feature will be regressed.
config USB_DWC3_GADGET
bool "Gadget only mode"
- depends on USB_GADGET
+ depends on USB_GADGET=y || USB_GADGET=USB_DWC3
help
Select this when you want to use DWC3 in gadget mode only,
thereby the host feature will be regressed.
config USB_DWC3_DUAL_ROLE
bool "Dual Role mode"
- depends on (USB && USB_GADGET)
+ depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
help
This is the default mode of working of DWC3 controller where
both host and gadget features are enabled.
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
index a8afe6e..8ce9d7f 100644
--- a/drivers/usb/dwc3/dwc3-exynos.c
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -95,8 +95,6 @@ static int dwc3_exynos_remove_child(struct device *dev, void *unused)
return 0;
}
-static u64 dwc3_exynos_dma_mask = DMA_BIT_MASK(32);
-
static int dwc3_exynos_probe(struct platform_device *pdev)
{
struct dwc3_exynos *exynos;
@@ -118,7 +116,9 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
* Once we move to full device tree support this will vanish off.
*/
if (!dev->dma_mask)
- dev->dma_mask = &dwc3_exynos_dma_mask;
+ dev->dma_mask = &dev->coherent_dma_mask;
+ if (!dev->coherent_dma_mask)
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
platform_set_drvdata(pdev, exynos);
@@ -164,9 +164,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev)
{
struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
+ device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
- device_for_each_child(&pdev->dev, NULL, dwc3_exynos_remove_child);
clk_disable_unprepare(exynos->clk);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 227d4a7..eba9e2b 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -196,9 +196,9 @@ static void dwc3_pci_remove(struct pci_dev *pci)
{
struct dwc3_pci *glue = pci_get_drvdata(pci);
+ platform_device_unregister(glue->dwc3);
platform_device_unregister(glue->usb2_phy);
platform_device_unregister(glue->usb3_phy);
- platform_device_unregister(glue->dwc3);
pci_set_drvdata(pci, NULL);
pci_disable_device(pci);
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2b6e7e0..b5e5b35 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1706,11 +1706,19 @@ static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
dep = dwc->eps[epnum];
if (!dep)
continue;
-
- dwc3_free_trb_pool(dep);
-
- if (epnum != 0 && epnum != 1)
+ /*
+ * Physical endpoints 0 and 1 are special; they form the
+ * bi-directional USB endpoint 0.
+ *
+ * For those two physical endpoints, we don't allocate a TRB
+ * pool nor do we add them the endpoints list. Due to that, we
+ * shouldn't do these two operations otherwise we would end up
+ * with all sorts of bugs when removing dwc3.ko.
+ */
+ if (epnum != 0 && epnum != 1) {
+ dwc3_free_trb_pool(dep);
list_del(&dep->endpoint.ep_list);
+ }
kfree(dep);
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 83300d9..f41aa0d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -146,7 +146,6 @@ config USB_LPC32XX
depends on ARCH_LPC32XX
depends on USB_PHY
select USB_ISP1301
- select USB_OTG_UTILS
help
This option selects the USB device controller in the LPC32xx SoC.
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index f2a970f..5a5128a 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1992,8 +1992,6 @@ err_map_regs:
err_get_hclk:
clk_put(pclk);
- platform_set_drvdata(pdev, NULL);
-
return ret;
}
diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c
index 6e65182..fd24cb4 100644
--- a/drivers/usb/gadget/bcm63xx_udc.c
+++ b/drivers/usb/gadget/bcm63xx_udc.c
@@ -2334,21 +2334,11 @@ static int bcm63xx_udc_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "error finding USBD resource\n");
- return -ENXIO;
- }
-
udc->usbd_regs = devm_ioremap_resource(dev, res);
if (IS_ERR(udc->usbd_regs))
return PTR_ERR(udc->usbd_regs);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- dev_err(dev, "error finding IUDMA resource\n");
- return -ENXIO;
- }
-
udc->iudma_regs = devm_ioremap_resource(dev, res);
if (IS_ERR(udc->iudma_regs))
return PTR_ERR(udc->iudma_regs);
@@ -2420,7 +2410,6 @@ static int bcm63xx_udc_remove(struct platform_device *pdev)
usb_del_gadget_udc(&udc->gadget);
BUG_ON(udc->driver);
- platform_set_drvdata(pdev, NULL);
bcm63xx_uninit_udc_hw(udc);
return 0;
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 3d5cfc9..80e7f75 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -821,8 +821,10 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
gi->gstrings[i] = NULL;
s = usb_gstrings_attach(&gi->cdev, gi->gstrings,
USB_GADGET_FIRST_AVAIL_IDX);
- if (IS_ERR(s))
+ if (IS_ERR(s)) {
+ ret = PTR_ERR(s);
goto err_comp_cleanup;
+ }
gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
@@ -847,8 +849,10 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
}
cfg->gstrings[i] = NULL;
s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1);
- if (IS_ERR(s))
+ if (IS_ERR(s)) {
+ ret = PTR_ERR(s);
goto err_comp_cleanup;
+ }
c->iConfiguration = s[0].id;
}
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index a792e32..c588e8e 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -1001,7 +1001,6 @@ static int dummy_udc_remove(struct platform_device *pdev)
struct dummy *dum = platform_get_drvdata(pdev);
usb_del_gadget_udc(&dum->gadget);
- platform_set_drvdata(pdev, NULL);
device_remove_file(&dum->gadget.dev, &dev_attr_function);
return 0;
}
@@ -2661,8 +2660,10 @@ static int __init init(void)
}
for (i = 0; i < mod_data.num; i++) {
dum[i] = kzalloc(sizeof(struct dummy), GFP_KERNEL);
- if (!dum[i])
+ if (!dum[i]) {
+ retval = -ENOMEM;
goto err_add_pdata;
+ }
retval = platform_device_add_data(the_hcd_pdev[i], &dum[i],
sizeof(void *));
if (retval)
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index d893d69..abf8a31 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -816,6 +816,7 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
* @c: the configuration to support the network link
* @ethaddr: a buffer in which the ethernet address of the host side
* side of the link was recorded
+ * @dev: eth_dev structure
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 185d6f5..7be04b3 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -373,6 +373,7 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f)
* @c: the configuration to support the network link
* @ethaddr: a buffer in which the ethernet address of the host side
* side of the link was recorded
+ * @dev: eth_dev structure
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c
index c7468b6..03c1fb6 100644
--- a/drivers/usb/gadget/f_uac2.c
+++ b/drivers/usb/gadget/f_uac2.c
@@ -456,8 +456,6 @@ static int snd_uac2_remove(struct platform_device *pdev)
{
struct snd_card *card = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
if (card)
return snd_card_free(card);
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index cec8871..b8632d40 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -1461,8 +1461,10 @@ static int __init fusb300_probe(struct platform_device *pdev)
fusb300->ep0_req = fusb300_alloc_request(&fusb300->ep[0]->ep,
GFP_KERNEL);
- if (fusb300->ep0_req == NULL)
+ if (fusb300->ep0_req == NULL) {
+ ret = -ENOMEM;
goto clean_up3;
+ }
init_controller(fusb300);
ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget);
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index b5cebd6..9b2d24e 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1511,8 +1511,6 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
if (pdata->exit)
pdata->exit(&pdev->dev);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 866ef09..51cfe72 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1660,8 +1660,10 @@ static int __init m66592_probe(struct platform_device *pdev)
m66592->epaddr2ep[0] = &m66592->ep[0];
m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
- if (m66592->ep0_req == NULL)
+ if (m66592->ep0_req == NULL) {
+ ret = -ENOMEM;
goto clean_up3;
+ }
m66592->ep0_req->complete = nop_completion;
init_controller(m66592);
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index ef47495..95c531d 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -2236,7 +2236,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
dev->transceiver = NULL;
}
- platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;
}
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index 0b742d1..7ff7d9c 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1977,8 +1977,10 @@ static int __init r8a66597_probe(struct platform_device *pdev)
r8a66597->ep0_req = r8a66597_alloc_request(&r8a66597->ep[0].ep,
GFP_KERNEL);
- if (r8a66597->ep0_req == NULL)
+ if (r8a66597->ep0_req == NULL) {
+ ret = -ENOMEM;
goto clean_up3;
+ }
r8a66597->ep0_req->complete = nop_completion;
ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget);
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index a3cdc32..af22f24 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -437,7 +437,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
if (hs_req->req.length == 0)
return;
- usb_gadget_unmap_request(&hsotg->gadget, hs_req, hs_ep->dir_in);
+ usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in);
}
/**
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index d0e75e1..09c4f70 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1851,6 +1851,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
irq = gpio_to_irq(udc_info->vbus_pin);
if (irq < 0) {
dev_err(dev, "no irq for gpio vbus pin\n");
+ retval = irq;
goto err_gpio_claim;
}
@@ -1948,8 +1949,6 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
iounmap(base_addr);
release_mem_region(rsrc_start, rsrc_len);
- platform_set_drvdata(pdev, NULL);
-
if (!IS_ERR(udc_clock) && udc_clock != NULL) {
clk_disable(udc_clock);
clk_put(udc_clock);
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 2cd6262..0deb9d6 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -284,12 +284,16 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
ss_opts->bulk_buflen = gzero_options.bulk_buflen;
func_ss = usb_get_function(func_inst_ss);
- if (IS_ERR(func_ss))
+ if (IS_ERR(func_ss)) {
+ status = PTR_ERR(func_ss);
goto err_put_func_inst_ss;
+ }
func_inst_lb = usb_get_function_instance("Loopback");
- if (IS_ERR(func_inst_lb))
+ if (IS_ERR(func_inst_lb)) {
+ status = PTR_ERR(func_inst_lb);
goto err_put_func_ss;
+ }
lb_opts = container_of(func_inst_lb, struct f_lb_opts, func_inst);
lb_opts->bulk_buflen = gzero_options.bulk_buflen;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index de94f26..344d5e2 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -507,7 +507,7 @@ endif # USB_OHCI_HCD
config USB_UHCI_HCD
tristate "UHCI HCD (most Intel and VIA) support"
- depends on PCI || SPARC_LEON || ARCH_VT8500
+ depends on PCI || USB_UHCI_SUPPORT_NON_PCI_HC
---help---
The Universal Host Controller Interface is a standard by Intel for
accessing the USB hardware in the PC (which is also called the USB
@@ -524,26 +524,19 @@ config USB_UHCI_HCD
config USB_UHCI_SUPPORT_NON_PCI_HC
bool
- depends on USB_UHCI_HCD
- default y if (SPARC_LEON || ARCH_VT8500)
+ default y if (SPARC_LEON || USB_UHCI_PLATFORM)
config USB_UHCI_PLATFORM
- bool "Generic UHCI Platform Driver support"
- depends on USB_UHCI_SUPPORT_NON_PCI_HC
+ bool
default y if ARCH_VT8500
- ---help---
- Enable support for generic UHCI platform devices that require no
- additional configuration.
config USB_UHCI_BIG_ENDIAN_MMIO
bool
- depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON
- default y
+ default y if SPARC_LEON
config USB_UHCI_BIG_ENDIAN_DESC
bool
- depends on USB_UHCI_SUPPORT_NON_PCI_HC && SPARC_LEON
- default y
+ default y if SPARC_LEON
config USB_FHCI_HCD
tristate "Freescale QE USB Host Controller support"
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 6642009..02f4611 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -63,8 +63,6 @@ static void atmel_stop_ehci(struct platform_device *pdev)
/*-------------------------------------------------------------------------*/
-static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32);
-
static int ehci_atmel_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -93,7 +91,9 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
* Once we have dma capability bindings this can go away.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &at91_ehci_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 312fc10..246e124 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1286,23 +1286,6 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_sead3_driver
#endif
-#if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \
- !IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \
- !IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \
- !IS_ENABLED(CONFIG_USB_EHCI_MXC) && \
- !IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \
- !IS_ENABLED(CONFIG_USB_EHCI_HCD_ORION) && \
- !IS_ENABLED(CONFIG_USB_EHCI_HCD_SPEAR) && \
- !IS_ENABLED(CONFIG_USB_EHCI_S5P) && \
- !IS_ENABLED(CONFIG_USB_EHCI_HCD_AT91) && \
- !IS_ENABLED(CONFIG_USB_EHCI_MSM) && \
- !defined(PLATFORM_DRIVER) && \
- !defined(PS3_SYSTEM_BUS_DRIVER) && \
- !defined(OF_PLATFORM_DRIVER) && \
- !defined(XILINX_OF_PLATFORM_DRIVER)
-#error "missing bus glue for ehci-hcd"
-#endif
-
static int __init ehci_hcd_init(void)
{
int retval = 0;
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 3d1491b..16d7150 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -90,8 +90,6 @@ static const struct ehci_driver_overrides ehci_omap_overrides __initdata = {
.extra_priv_size = sizeof(struct omap_hcd),
};
-static u64 omap_ehci_dma_mask = DMA_BIT_MASK(32);
-
/**
* ehci_hcd_omap_probe - initialize TI-based HCDs
*
@@ -146,8 +144,10 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
* Since shared usb code relies on it, set it here for now.
* Once we have dma capability bindings this can go away.
*/
- if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &omap_ehci_dma_mask;
+ if (!dev->dma_mask)
+ dev->dma_mask = &dev->coherent_dma_mask;
+ if (!dev->coherent_dma_mask)
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,
dev_name(dev));
diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c
index 54c5794..efbc588 100644
--- a/drivers/usb/host/ehci-orion.c
+++ b/drivers/usb/host/ehci-orion.c
@@ -137,8 +137,6 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
}
}
-static u64 ehci_orion_dma_mask = DMA_BIT_MASK(32);
-
static int ehci_orion_drv_probe(struct platform_device *pdev)
{
struct orion_ehci_data *pd = pdev->dev.platform_data;
@@ -183,7 +181,9 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)
* now. Once we have dma capability bindings this can go away.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &ehci_orion_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
if (!request_mem_region(res->start, resource_size(res),
ehci_orion_hc_driver.description)) {
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 6357752..379037f 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -71,8 +71,6 @@ static void s5p_setup_vbus_gpio(struct platform_device *pdev)
dev_err(dev, "can't request ehci vbus gpio %d", gpio);
}
-static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32);
-
static int s5p_ehci_probe(struct platform_device *pdev)
{
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
@@ -90,7 +88,7 @@ static int s5p_ehci_probe(struct platform_device *pdev)
* Once we move to full device tree support this will vanish off.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &ehci_s5p_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
if (!pdev->dev.coherent_dma_mask)
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
@@ -107,6 +105,7 @@ static int s5p_ehci_probe(struct platform_device *pdev)
if (IS_ERR(phy)) {
/* Fallback to pdata */
if (!pdata) {
+ usb_put_hcd(hcd);
dev_warn(&pdev->dev, "no platform data or transceiver defined\n");
return -EPROBE_DEFER;
} else {
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index acff5b8..f80d033 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -213,7 +213,7 @@ static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask)
}
static const unsigned char
-max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 125, 25 };
+max_tt_usecs[] = { 125, 125, 125, 125, 125, 125, 30, 0 };
/* carryover low/fullspeed bandwidth that crosses uframe boundries */
static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8])
@@ -646,6 +646,10 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
/* reschedule QH iff another request is queued */
if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
rc = qh_schedule(ehci, qh);
+ if (rc == 0) {
+ qh_refresh(ehci, qh);
+ qh_link_periodic(ehci, qh);
+ }
/* An error here likely indicates handshake failure
* or no space left in the schedule. Neither fault
@@ -653,9 +657,10 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
*
* FIXME kill the now-dysfunctional queued urbs
*/
- if (rc != 0)
+ else {
ehci_err(ehci, "can't reschedule qh %p, err %d\n",
qh, rc);
+ }
}
/* maybe turn off periodic schedule */
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 61ecfb3..bd3e5cb 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -58,8 +58,6 @@ static int ehci_spear_drv_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
ehci_spear_drv_resume);
-static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32);
-
static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd ;
@@ -84,7 +82,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
* Once we have dma capability bindings this can go away.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &spear_ehci_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
usbh_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(usbh_clk)) {
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index e3eddc3..59d111b 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -637,8 +637,6 @@ static void tegra_ehci_set_phcd(struct usb_phy *x, bool enable)
writel(val, base + TEGRA_USB_PORTSC1);
}
-static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32);
-
static int tegra_ehci_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -661,7 +659,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
* Once we have dma capability bindings this can go away.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &tegra_ehci_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
setup_vbus_gpio(pdev, pdata);
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 125e261..2facee5 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -1739,7 +1739,7 @@ static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
int retval = 1;
unsigned long flags;
- /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ /* if !PM_RUNTIME, root hub timers won't get shut down ... */
if (!HC_IS_RUNNING(hcd->state))
return 0;
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index bbb791b..a13709e 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -373,8 +373,10 @@ static int isp1760_plat_probe(struct platform_device *pdev)
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
pr_warning("isp1760: IRQ resource not available\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto cleanup;
}
+
irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
if (priv) {
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index a0cb44f..2ee1496 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -504,8 +504,6 @@ static const struct of_device_id at91_ohci_dt_ids[] = {
MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids);
-static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32);
-
static int ohci_at91_of_init(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -522,7 +520,9 @@ static int ohci_at91_of_init(struct platform_device *pdev)
* Once we have dma capability bindings this can go away.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &at91_ohci_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 07592c0..b0b542c 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -98,8 +98,6 @@ static const struct hc_driver exynos_ohci_hc_driver = {
.start_port_reset = ohci_start_port_reset,
};
-static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32);
-
static int exynos_ohci_probe(struct platform_device *pdev)
{
struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data;
@@ -117,7 +115,7 @@ static int exynos_ohci_probe(struct platform_device *pdev)
* Once we move to full device tree support this will vanish off.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &ohci_exynos_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
if (!pdev->dev.coherent_dma_mask)
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 9e6de95..fc627fd 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -233,14 +233,14 @@ static int ohci_urb_enqueue (
urb->start_frame = frame;
}
} else if (ed->type == PIPE_ISOCHRONOUS) {
- u16 next = ohci_frame_no(ohci) + 2;
+ u16 next = ohci_frame_no(ohci) + 1;
u16 frame = ed->last_iso + ed->interval;
/* Behind the scheduling threshold? */
if (unlikely(tick_before(frame, next))) {
/* USB_ISO_ASAP: Round up to the first available slot */
- if (urb->transfer_flags & URB_ISO_ASAP)
+ if (urb->transfer_flags & URB_ISO_ASAP) {
frame += (next - frame + ed->interval - 1) &
-ed->interval;
@@ -248,21 +248,25 @@ static int ohci_urb_enqueue (
* Not ASAP: Use the next slot in the stream. If
* the entire URB falls before the threshold, fail.
*/
- else if (tick_before(frame + ed->interval *
+ } else {
+ if (tick_before(frame + ed->interval *
(urb->number_of_packets - 1), next)) {
- retval = -EXDEV;
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- goto fail;
- }
+ retval = -EXDEV;
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ goto fail;
+ }
- /*
- * Some OHCI hardware doesn't handle late TDs
- * correctly. After retiring them it proceeds to
- * the next ED instead of the next TD. Therefore
- * we have to omit the late TDs entirely.
- */
- urb_priv->td_cnt = DIV_ROUND_UP(next - frame,
- ed->interval);
+ /*
+ * Some OHCI hardware doesn't handle late TDs
+ * correctly. After retiring them it proceeds
+ * to the next ED instead of the next TD.
+ * Therefore we have to omit the late TDs
+ * entirely.
+ */
+ urb_priv->td_cnt = DIV_ROUND_UP(
+ (u16) (next - frame),
+ ed->interval);
+ }
}
urb->start_frame = frame;
}
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index f4988fb..5d7eb72 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -223,8 +223,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
isp1301_i2c_client = isp1301_get_client(isp1301_node);
if (!isp1301_i2c_client) {
- ret = -EPROBE_DEFER;
- goto out;
+ return -EPROBE_DEFER;
}
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
@@ -234,7 +233,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
if (usb_disabled()) {
dev_err(&pdev->dev, "USB is disabled\n");
ret = -ENODEV;
- goto out;
+ goto fail_disable;
}
/* Enable AHB slave USB clock, needed for further USB clock control */
@@ -245,19 +244,19 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
if (IS_ERR(usb_pll_clk)) {
dev_err(&pdev->dev, "failed to acquire USB PLL\n");
ret = PTR_ERR(usb_pll_clk);
- goto out1;
+ goto fail_pll;
}
ret = clk_enable(usb_pll_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to start USB PLL\n");
- goto out2;
+ goto fail_pllen;
}
ret = clk_set_rate(usb_pll_clk, 48000);
if (ret < 0) {
dev_err(&pdev->dev, "failed to set USB clock rate\n");
- goto out3;
+ goto fail_rate;
}
/* Enable USB device clock */
@@ -265,13 +264,13 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
if (IS_ERR(usb_dev_clk)) {
dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
ret = PTR_ERR(usb_dev_clk);
- goto out4;
+ goto fail_dev;
}
ret = clk_enable(usb_dev_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
- goto out5;
+ goto fail_deven;
}
/* Enable USB otg clocks */
@@ -279,7 +278,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
if (IS_ERR(usb_otg_clk)) {
dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");
ret = PTR_ERR(usb_otg_clk);
- goto out6;
+ goto fail_otg;
}
__raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
@@ -287,7 +286,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
ret = clk_enable(usb_otg_clk);
if (ret < 0) {
dev_err(&pdev->dev, "failed to start USB DEV Clock\n");
- goto out7;
+ goto fail_otgen;
}
isp1301_configure();
@@ -296,20 +295,14 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
if (!hcd) {
dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
ret = -ENOMEM;
- goto out8;
+ goto fail_hcd;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Failed to get MEM resource\n");
- ret = -ENOMEM;
- goto out8;
- }
-
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
ret = PTR_ERR(hcd->regs);
- goto out8;
+ goto fail_resource;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
@@ -317,7 +310,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = -ENXIO;
- goto out8;
+ goto fail_resource;
}
nxp_start_hc();
@@ -331,23 +324,24 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)
return ret;
nxp_stop_hc();
-out8:
+fail_resource:
usb_put_hcd(hcd);
-out7:
+fail_hcd:
clk_disable(usb_otg_clk);
-out6:
+fail_otgen:
clk_put(usb_otg_clk);
-out5:
+fail_otg:
clk_disable(usb_dev_clk);
-out4:
+fail_deven:
clk_put(usb_dev_clk);
-out3:
+fail_dev:
+fail_rate:
clk_disable(usb_pll_clk);
-out2:
+fail_pllen:
clk_put(usb_pll_clk);
-out1:
+fail_pll:
+fail_disable:
isp1301_i2c_client = NULL;
-out:
return ret;
}
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
index ddfc314..8663851 100644
--- a/drivers/usb/host/ohci-omap3.c
+++ b/drivers/usb/host/ohci-omap3.c
@@ -114,8 +114,6 @@ static const struct hc_driver ohci_omap3_hc_driver = {
/*-------------------------------------------------------------------------*/
-static u64 omap_ohci_dma_mask = DMA_BIT_MASK(32);
-
/*
* configure so an HC device and id are always provided
* always called with process context; sleeping is OK
@@ -168,8 +166,10 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)
* Since shared usb code relies on it, set it here for now.
* Once we have dma capability bindings this can go away.
*/
- if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &omap_ohci_dma_mask;
+ if (!dev->dma_mask)
+ dev->dma_mask = &dev->coherent_dma_mask;
+ if (!dev->coherent_dma_mask)
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,
dev_name(dev));
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index efe71f3..279b2ef 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -282,8 +282,6 @@ static const struct of_device_id pxa_ohci_dt_ids[] = {
MODULE_DEVICE_TABLE(of, pxa_ohci_dt_ids);
-static u64 pxa_ohci_dma_mask = DMA_BIT_MASK(32);
-
static int ohci_pxa_of_init(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -298,7 +296,9 @@ static int ohci_pxa_of_init(struct platform_device *pdev)
* Once we have dma capability bindings this can go away.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &pxa_ohci_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 9020bf0..3e19e01 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -91,8 +91,6 @@ static const struct hc_driver ohci_spear_hc_driver = {
.start_port_reset = ohci_start_port_reset,
};
-static u64 spear_ohci_dma_mask = DMA_BIT_MASK(32);
-
static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
{
const struct hc_driver *driver = &ohci_spear_hc_driver;
@@ -114,7 +112,9 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
* Once we have dma capability bindings this can go away.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &spear_ohci_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
usbh_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(usbh_clk)) {
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 4f0f033..0f401db 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -3084,7 +3084,7 @@ static int oxu_hub_status_data(struct usb_hcd *hcd, char *buf)
int ports, i, retval = 1;
unsigned long flags;
- /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ /* if !PM_RUNTIME, root hub timers won't get shut down ... */
if (!HC_IS_RUNNING(hcd->state))
return 0;
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index ad4483e..b2ec7fe 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -22,7 +22,7 @@
* and usb-storage.
*
* TODO:
- * - usb suspend/resume triggered by sl811 (with USB_SUSPEND)
+ * - usb suspend/resume triggered by sl811 (with PM_RUNTIME)
* - various issues noted in the code
* - performance work; use both register banks; ...
* - use urb->iso_frame_desc[] with ISO transfers
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index f87bee6..9189bc9 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -225,7 +225,8 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
/* auto-stop if nothing connected for 1 second */
if (any_ports_active(uhci))
uhci->rh_state = UHCI_RH_RUNNING;
- else if (time_after_eq(jiffies, uhci->auto_stop_time))
+ else if (time_after_eq(jiffies, uhci->auto_stop_time) &&
+ !uhci->wait_for_hp)
suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
break;
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index 8c4dace..f1db61a 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -60,8 +60,6 @@ static const struct hc_driver uhci_platform_hc_driver = {
.hub_control = uhci_hub_control,
};
-static u64 platform_uhci_dma_mask = DMA_BIT_MASK(32);
-
static int uhci_hcd_platform_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -78,7 +76,9 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)
* Once we have dma capability bindings this can go away.
*/
if (!pdev->dev.dma_mask)
- pdev->dev.dma_mask = &platform_uhci_dma_mask;
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev,
pdev->name);
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index f0976d8..041c6dd 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -1287,7 +1287,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
return -EINVAL; /* Can't change the period */
} else {
- next = uhci->frame_number + 2;
+ next = uhci->frame_number + 1;
/* Find the next unused frame */
if (list_empty(&qh->queue)) {
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 965b539..fbf75e5 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1423,15 +1423,17 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
ep_ctx->ep_info2 |= cpu_to_le32(xhci_get_endpoint_type(udev, ep));
/* Set the max packet size and max burst */
+ max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
+ max_burst = 0;
switch (udev->speed) {
case USB_SPEED_SUPER:
- max_packet = usb_endpoint_maxp(&ep->desc);
- ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
/* dig out max burst from ep companion desc */
- max_packet = ep->ss_ep_comp.bMaxBurst;
- ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_packet));
+ max_burst = ep->ss_ep_comp.bMaxBurst;
break;
case USB_SPEED_HIGH:
+ /* Some devices get this wrong */
+ if (usb_endpoint_xfer_bulk(&ep->desc))
+ max_packet = 512;
/* bits 11:12 specify the number of additional transaction
* opportunities per microframe (USB 2.0, section 9.6.6)
*/
@@ -1439,17 +1441,16 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
usb_endpoint_xfer_int(&ep->desc)) {
max_burst = (usb_endpoint_maxp(&ep->desc)
& 0x1800) >> 11;
- ep_ctx->ep_info2 |= cpu_to_le32(MAX_BURST(max_burst));
}
- /* Fall through */
+ break;
case USB_SPEED_FULL:
case USB_SPEED_LOW:
- max_packet = GET_MAX_PACKET(usb_endpoint_maxp(&ep->desc));
- ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet));
break;
default:
BUG();
}
+ ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet) |
+ MAX_BURST(max_burst));
max_esit_payload = xhci_get_max_esit_payload(xhci, udev, ep);
ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload));
@@ -1826,6 +1827,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
}
spin_unlock_irqrestore(&xhci->lock, flags);
+ if (!xhci->rh_bw)
+ goto no_bw;
+
num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
for (i = 0; i < num_ports; i++) {
struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table;
@@ -1844,6 +1848,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
}
}
+no_bw:
xhci->num_usb2_ports = 0;
xhci->num_usb3_ports = 0;
xhci->num_active_eps = 0;
@@ -2255,6 +2260,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
u32 page_size, temp;
int i;
+ INIT_LIST_HEAD(&xhci->lpm_failed_devs);
+ INIT_LIST_HEAD(&xhci->cancel_cmd_list);
+
page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size);
for (i = 0; i < 16; i++) {
@@ -2333,7 +2341,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
if (!xhci->cmd_ring)
goto fail;
- INIT_LIST_HEAD(&xhci->cancel_cmd_list);
xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
(unsigned long long)xhci->cmd_ring->first_seg->dma);
@@ -2444,8 +2451,6 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
if (xhci_setup_port_arrays(xhci, flags))
goto fail;
- INIT_LIST_HEAD(&xhci->lpm_failed_devs);
-
/* Enable USB 3.0 device notifications for function remote wake, which
* is necessary for allowing USB 3.0 devices to do remote wakeup from
* U3 (device suspend).
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 1a30c38..cc24e39 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -221,6 +221,14 @@ static void xhci_pci_remove(struct pci_dev *dev)
static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+
+ /*
+ * Systems with the TI redriver that loses port status change events
+ * need to have the registers polled during D3, so avoid D3cold.
+ */
+ if (xhci_compliance_mode_recovery_timer_quirk_check())
+ pdev->no_d3cold = true;
return xhci_suspend(xhci);
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index b4aa79d..d8f640b 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -466,7 +466,7 @@ static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
* Systems:
* Vendor: Hewlett-Packard -> System Models: Z420, Z620 and Z820
*/
-static bool compliance_mode_recovery_timer_quirk_check(void)
+bool xhci_compliance_mode_recovery_timer_quirk_check(void)
{
const char *dmi_product_name, *dmi_sys_vendor;
@@ -517,7 +517,7 @@ int xhci_init(struct usb_hcd *hcd)
xhci_dbg(xhci, "Finished xhci_init\n");
/* Initializing Compliance Mode Recovery Data If Needed */
- if (compliance_mode_recovery_timer_quirk_check()) {
+ if (xhci_compliance_mode_recovery_timer_quirk_check()) {
xhci->quirks |= XHCI_COMP_MODE_QUIRK;
compliance_mode_recovery_timer_init(xhci);
}
@@ -956,6 +956,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct usb_hcd *secondary_hcd;
int retval = 0;
+ bool comp_timer_running = false;
/* Wait a bit if either of the roothubs need to settle from the
* transition into bus suspend.
@@ -993,6 +994,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
/* If restore operation fails, re-initialize the HC during resume */
if ((temp & STS_SRE) || hibernated) {
+
+ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) &&
+ !(xhci_all_ports_seen_u0(xhci))) {
+ del_timer_sync(&xhci->comp_mode_recovery_timer);
+ xhci_dbg(xhci, "Compliance Mode Recovery Timer deleted!\n");
+ }
+
/* Let the USB core know _both_ roothubs lost power. */
usb_root_hub_lost_power(xhci->main_hcd->self.root_hub);
usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub);
@@ -1035,6 +1043,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
retval = xhci_init(hcd->primary_hcd);
if (retval)
return retval;
+ comp_timer_running = true;
+
xhci_dbg(xhci, "Start the primary HCD\n");
retval = xhci_run(hcd->primary_hcd);
if (!retval) {
@@ -1076,7 +1086,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
* to suffer the Compliance Mode issue again. It doesn't matter if
* ports have entered previously to U0 before system's suspension.
*/
- if (xhci->quirks & XHCI_COMP_MODE_QUIRK)
+ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && !comp_timer_running)
compliance_mode_recovery_timer_init(xhci);
/* Re-enable port polling. */
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 29c978e..77600ce 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1853,4 +1853,7 @@ struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci,
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
+/* xHCI quirks */
+bool xhci_compliance_mode_recovery_timer_quirk_check(void);
+
#endif /* __LINUX_XHCI_HCD_H */
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
index 3a18e44..e1b661d 100644
--- a/drivers/usb/musb/musb_dsps.c
+++ b/drivers/usb/musb/musb_dsps.c
@@ -560,6 +560,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
if (!config) {
dev_err(&pdev->dev,
"failed to allocate musb hdrc config\n");
+ ret = -ENOMEM;
goto err2;
}
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 8914dec..9d3044b 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -1232,7 +1232,6 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem *mbase = musb->mregs;
struct dma_channel *dma;
bool transfer_pending = false;
- static bool use_sg;
musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR);
@@ -1463,9 +1462,9 @@ done:
* NULL.
*/
if (!urb->transfer_buffer)
- use_sg = true;
+ qh->use_sg = true;
- if (use_sg) {
+ if (qh->use_sg) {
/* sg_miter_start is already done in musb_ep_program */
if (!sg_miter_next(&qh->sg_miter)) {
dev_err(musb->controller, "error: sg list empty\n");
@@ -1484,9 +1483,9 @@ done:
qh->segsize = length;
- if (use_sg) {
+ if (qh->use_sg) {
if (offset + length >= urb->transfer_buffer_length)
- use_sg = false;
+ qh->use_sg = false;
}
musb_ep_select(mbase, epnum);
@@ -1552,7 +1551,6 @@ void musb_host_rx(struct musb *musb, u8 epnum)
bool done = false;
u32 status;
struct dma_channel *dma;
- static bool use_sg;
unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
musb_ep_select(mbase, epnum);
@@ -1878,12 +1876,12 @@ void musb_host_rx(struct musb *musb, u8 epnum)
* NULL.
*/
if (!urb->transfer_buffer) {
- use_sg = true;
+ qh->use_sg = true;
sg_miter_start(&qh->sg_miter, urb->sg, 1,
sg_flags);
}
- if (use_sg) {
+ if (qh->use_sg) {
if (!sg_miter_next(&qh->sg_miter)) {
dev_err(musb->controller, "error: sg list empty\n");
sg_miter_stop(&qh->sg_miter);
@@ -1913,8 +1911,8 @@ finish:
urb->actual_length += xfer_len;
qh->offset += xfer_len;
if (done) {
- if (use_sg)
- use_sg = false;
+ if (qh->use_sg)
+ qh->use_sg = false;
if (urb->status == -EINPROGRESS)
urb->status = status;
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
index 5a9c8fe..738f7eb 100644
--- a/drivers/usb/musb/musb_host.h
+++ b/drivers/usb/musb/musb_host.h
@@ -74,6 +74,7 @@ struct musb_qh {
u16 frame; /* for periodic schedule */
unsigned iso_idx; /* in urb->iso_frame_desc[] */
struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */
+ bool use_sg; /* to track urb using sglist */
};
/* map from control or bulk queue head to the first qh on that ring */
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index 3551f1a..628b93f 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -549,7 +549,8 @@ static int omap2430_probe(struct platform_device *pdev)
glue->control_otghs = omap_get_control_dev();
if (IS_ERR(glue->control_otghs)) {
dev_vdbg(&pdev->dev, "Failed to get control device\n");
- return -ENODEV;
+ ret = PTR_ERR(glue->control_otghs);
+ goto err2;
}
} else {
glue->control_otghs = ERR_PTR(-ENODEV);
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 371d0e7..7ef3eb8 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -25,7 +25,7 @@ config AB8500_USB
config FSL_USB2_OTG
bool "Freescale USB OTG Transceiver Driver"
- depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_SUSPEND
+ depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME
select USB_OTG
help
Enable this to support Freescale USB OTG transceiver.
@@ -139,7 +139,6 @@ config USB_ISP1301
tristate "NXP ISP1301 USB transceiver support"
depends on USB || USB_GADGET
depends on I2C
- select USB_OTG_UTILS
help
Say Y here to add support for the NXP ISP1301 USB transceiver driver.
This chip is typically used as USB transceiver for USB host, gadget
@@ -162,7 +161,7 @@ config USB_MSM_OTG
config USB_MV_OTG
tristate "Marvell USB OTG support"
- depends on USB_EHCI_MV && USB_MV_UDC && USB_SUSPEND
+ depends on USB_EHCI_MV && USB_MV_UDC && PM_RUNTIME
select USB_OTG
help
Say Y here if you want to build Marvell USB OTG transciever
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c
index 4acef26..e5eb1b5 100644
--- a/drivers/usb/phy/phy-ab8500-usb.c
+++ b/drivers/usb/phy/phy-ab8500-usb.c
@@ -892,8 +892,6 @@ static int ab8500_usb_remove(struct platform_device *pdev)
else if (ab->mode == USB_PERIPHERAL)
ab8500_usb_peri_phy_dis(ab);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index 97b9308..e771baf 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -799,6 +799,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
/* initialize the otg structure */
fsl_otg_tc->phy.label = DRIVER_DESC;
+ fsl_otg_tc->phy.dev = &pdev->dev;
fsl_otg_tc->phy.set_power = fsl_otg_set_power;
fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy;
diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c
index 4c76074..8443335 100644
--- a/drivers/usb/phy/phy-gpio-vbus-usb.c
+++ b/drivers/usb/phy/phy-gpio-vbus-usb.c
@@ -266,6 +266,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gpio_vbus);
gpio_vbus->dev = &pdev->dev;
gpio_vbus->phy.label = "gpio-vbus";
+ gpio_vbus->phy.dev = gpio_vbus->dev;
gpio_vbus->phy.set_power = gpio_vbus_set_power;
gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend;
gpio_vbus->phy.state = OTG_STATE_UNDEFINED;
@@ -343,7 +344,6 @@ err_irq:
gpio_free(pdata->gpio_pullup);
gpio_free(pdata->gpio_vbus);
err_gpio:
- platform_set_drvdata(pdev, NULL);
kfree(gpio_vbus->phy.otg);
kfree(gpio_vbus);
return err;
@@ -365,7 +365,6 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev)
if (gpio_is_valid(pdata->gpio_pullup))
gpio_free(pdata->gpio_pullup);
gpio_free(gpio);
- platform_set_drvdata(pdev, NULL);
kfree(gpio_vbus->phy.otg);
kfree(gpio_vbus);
diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c
index 225ae6c..8a55b37 100644
--- a/drivers/usb/phy/phy-isp1301.c
+++ b/drivers/usb/phy/phy-isp1301.c
@@ -102,6 +102,7 @@ static int isp1301_probe(struct i2c_client *client,
mutex_init(&isp->mutex);
phy = &isp->phy;
+ phy->dev = &client->dev;
phy->label = DRV_NAME;
phy->init = isp1301_phy_init;
phy->set_vbus = isp1301_phy_set_vbus;
diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c
index f7838a4..1568ea6 100644
--- a/drivers/usb/phy/phy-mv-u3d-usb.c
+++ b/drivers/usb/phy/phy-mv-u3d-usb.c
@@ -278,11 +278,6 @@ static int mv_u3d_phy_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "missing mem resource\n");
- return -ENODEV;
- }
-
phy_base = devm_ioremap_resource(dev, res);
if (IS_ERR(phy_base))
return PTR_ERR(phy_base);
diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c
index c987bbe..4a6b03c 100644
--- a/drivers/usb/phy/phy-mv-usb.c
+++ b/drivers/usb/phy/phy-mv-usb.c
@@ -667,7 +667,6 @@ int mv_otg_remove(struct platform_device *pdev)
mv_otg_disable(mvotg);
usb_remove_phy(&mvotg->phy);
- platform_set_drvdata(pdev, NULL);
return 0;
}
@@ -850,8 +849,6 @@ err_destroy_workqueue:
flush_workqueue(mvotg->qwork);
destroy_workqueue(mvotg->qwork);
- platform_set_drvdata(pdev, NULL);
-
return retval;
}
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index 9d4381e..bd601c5 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -130,11 +130,6 @@ static int mxs_phy_probe(struct platform_device *pdev)
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "can't get device resources\n");
- return -ENOENT;
- }
-
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -160,6 +155,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
mxs_phy->phy.set_suspend = mxs_phy_suspend;
mxs_phy->phy.notify_connect = mxs_phy_on_connect;
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
+ mxs_phy->phy.type = USB_PHY_TYPE_USB2;
ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier);
@@ -180,8 +176,6 @@ static int mxs_phy_remove(struct platform_device *pdev)
usb_remove_phy(&mxs_phy->phy);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/usb/phy/phy-nop.c b/drivers/usb/phy/phy-nop.c
index 2b10cc9..638cc5d 100644
--- a/drivers/usb/phy/phy-nop.c
+++ b/drivers/usb/phy/phy-nop.c
@@ -254,8 +254,6 @@ static int nop_usb_xceiv_remove(struct platform_device *pdev)
usb_remove_phy(&nop->phy);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c
index 45ffe03..9d5e273 100644
--- a/drivers/usb/phy/phy-samsung-usb2.c
+++ b/drivers/usb/phy/phy-samsung-usb2.c
@@ -363,11 +363,6 @@ static int samsung_usb2phy_probe(struct platform_device *pdev)
int ret;
phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!phy_mem) {
- dev_err(dev, "%s: missing mem resource\n", __func__);
- return -ENODEV;
- }
-
phy_base = devm_ioremap_resource(dev, phy_mem);
if (IS_ERR(phy_base))
return PTR_ERR(phy_base);
diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c
index 133f3d0..5a9efcb 100644
--- a/drivers/usb/phy/phy-samsung-usb3.c
+++ b/drivers/usb/phy/phy-samsung-usb3.c
@@ -239,11 +239,6 @@ static int samsung_usb3phy_probe(struct platform_device *pdev)
int ret;
phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!phy_mem) {
- dev_err(dev, "%s: missing mem resource\n", __func__);
- return -ENODEV;
- }
-
phy_base = devm_ioremap_resource(dev, phy_mem);
if (IS_ERR(phy_base))
return PTR_ERR(phy_base);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 3b16118..40e7fd9 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -43,7 +43,7 @@
#define DRIVER_NAME "ark3116"
/* usb timeout of 1 second */
-#define ARK_TIMEOUT (1*HZ)
+#define ARK_TIMEOUT 1000
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x6547, 0x0232) },
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index d341555..0821201 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -65,6 +65,7 @@ static const struct usb_device_id id_table_earthmate[] = {
static const struct usb_device_id id_table_cyphidcomrs232[] = {
{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
+ { USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) },
{ } /* Terminating entry */
};
@@ -78,6 +79,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
{ USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
{ USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
+ { USB_DEVICE(VENDOR_ID_FRWD, PRODUCT_ID_CYPHIDCOM_FRWD) },
{ USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
{ } /* Terminating entry */
};
@@ -229,6 +231,12 @@ static struct usb_serial_driver * const serial_drivers[] = {
* Cypress serial helper functions
*****************************************************************************/
+/* FRWD Dongle hidcom needs to skip reset and speed checks */
+static inline bool is_frwd(struct usb_device *dev)
+{
+ return ((le16_to_cpu(dev->descriptor.idVendor) == VENDOR_ID_FRWD) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == PRODUCT_ID_CYPHIDCOM_FRWD));
+}
static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
{
@@ -238,6 +246,10 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
if (unstable_bauds)
return new_rate;
+ /* FRWD Dongle uses 115200 bps */
+ if (is_frwd(port->serial->dev))
+ return new_rate;
+
/*
* The general purpose firmware for the Cypress M8 allows for
* a maximum speed of 57600bps (I have no idea whether DeLorme
@@ -448,7 +460,11 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)
return -ENOMEM;
}
- usb_reset_configuration(serial->dev);
+ /* Skip reset for FRWD device. It is a workaound:
+ device hangs if it receives SET_CONFIGURE in Configured
+ state. */
+ if (!is_frwd(serial->dev))
+ usb_reset_configuration(serial->dev);
priv->cmd_ctrl = 0;
priv->line_control = 0;
diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h
index 67cf608..b461311 100644
--- a/drivers/usb/serial/cypress_m8.h
+++ b/drivers/usb/serial/cypress_m8.h
@@ -24,6 +24,10 @@
#define VENDOR_ID_CYPRESS 0x04b4
#define PRODUCT_ID_CYPHIDCOM 0x5500
+/* FRWD Dongle - a GPS sports watch */
+#define VENDOR_ID_FRWD 0x6737
+#define PRODUCT_ID_CYPHIDCOM_FRWD 0x0001
+
/* Powercom UPS, chip CY7C63723 */
#define VENDOR_ID_POWERCOM 0x0d9f
#define PRODUCT_ID_UPS 0x0002
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 090b411..7d8dd5a 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -165,11 +165,12 @@ static void f81232_set_termios(struct tty_struct *tty,
/* FIXME - Stubbed out for now */
/* Don't change anything if nothing has changed */
- if (!tty_termios_hw_change(&tty->termios, old_termios))
+ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
/* Do the real work here... */
- tty_termios_copy_hw(&tty->termios, old_termios);
+ if (old_termios)
+ tty_termios_copy_hw(&tty->termios, old_termios);
}
static int f81232_tiocmget(struct tty_struct *tty)
@@ -187,12 +188,11 @@ static int f81232_tiocmset(struct tty_struct *tty,
static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct ktermios tmp_termios;
int result;
/* Setup termios */
if (tty)
- f81232_set_termios(tty, port, &tmp_termios);
+ f81232_set_termios(tty, port, NULL);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 242b577..7260ec6 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -189,6 +189,8 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_GBM_BOOST_PID) },
{ USB_DEVICE(NEWPORT_VID, NEWPORT_AGILIS_PID) },
+ { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_CC_PID) },
+ { USB_DEVICE(NEWPORT_VID, NEWPORT_CONEX_AGP_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
@@ -924,8 +926,8 @@ static int ftdi_tiocmset(struct tty_struct *tty,
static int ftdi_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static void ftdi_break_ctl(struct tty_struct *tty, int break_state);
-static int ftdi_chars_in_buffer(struct tty_struct *tty);
-static int ftdi_get_modem_status(struct tty_struct *tty,
+static bool ftdi_tx_empty(struct usb_serial_port *port);
+static int ftdi_get_modem_status(struct usb_serial_port *port,
unsigned char status[2]);
static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
@@ -961,7 +963,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
- .chars_in_buffer = ftdi_chars_in_buffer,
+ .tx_empty = ftdi_tx_empty,
};
static struct usb_serial_driver * const serial_drivers[] = {
@@ -2056,27 +2058,18 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
}
-static int ftdi_chars_in_buffer(struct tty_struct *tty)
+static bool ftdi_tx_empty(struct usb_serial_port *port)
{
- struct usb_serial_port *port = tty->driver_data;
- int chars;
unsigned char buf[2];
int ret;
- chars = usb_serial_generic_chars_in_buffer(tty);
- if (chars)
- goto out;
-
- /* Check if hardware buffer is empty. */
- ret = ftdi_get_modem_status(tty, buf);
+ ret = ftdi_get_modem_status(port, buf);
if (ret == 2) {
if (!(buf[1] & FTDI_RS_TEMT))
- chars = 1;
+ return false;
}
-out:
- dev_dbg(&port->dev, "%s - %d\n", __func__, chars);
- return chars;
+ return true;
}
/* old_termios contains the original termios settings and tty->termios contains
@@ -2268,10 +2261,9 @@ no_c_cflag_changes:
* Returns the number of status bytes retrieved (device dependant), or
* negative error code.
*/
-static int ftdi_get_modem_status(struct tty_struct *tty,
+static int ftdi_get_modem_status(struct usb_serial_port *port,
unsigned char status[2])
{
- struct usb_serial_port *port = tty->driver_data;
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned char *buf;
int len;
@@ -2336,7 +2328,7 @@ static int ftdi_tiocmget(struct tty_struct *tty)
unsigned char buf[2];
int ret;
- ret = ftdi_get_modem_status(tty, buf);
+ ret = ftdi_get_modem_status(port, buf);
if (ret < 0)
return ret;
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 9852827..6dd7925 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -772,6 +772,8 @@
*/
#define NEWPORT_VID 0x104D
#define NEWPORT_AGILIS_PID 0x3000
+#define NEWPORT_CONEX_CC_PID 0x3002
+#define NEWPORT_CONEX_AGP_PID 0x3006
/* Interbiometrics USB I/O Board */
/* Developed for Interbiometrics by Rudolf Gugler */
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 297665f..ba45170 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -253,6 +253,37 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
}
EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer);
+void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ unsigned int bps;
+ unsigned long period;
+ unsigned long expire;
+
+ bps = tty_get_baud_rate(tty);
+ if (!bps)
+ bps = 9600; /* B0 */
+ /*
+ * Use a poll-period of roughly the time it takes to send one
+ * character or at least one jiffy.
+ */
+ period = max_t(unsigned long, (10 * HZ / bps), 1);
+ period = min_t(unsigned long, period, timeout);
+
+ dev_dbg(&port->dev, "%s - timeout = %u ms, period = %u ms\n",
+ __func__, jiffies_to_msecs(timeout),
+ jiffies_to_msecs(period));
+ expire = jiffies + timeout;
+ while (!port->serial->type->tx_empty(port)) {
+ schedule_timeout_interruptible(period);
+ if (signal_pending(current))
+ break;
+ if (time_after(jiffies, expire))
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(usb_serial_generic_wait_until_sent);
+
static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
int index, gfp_t mem_flags)
{
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 158bf4b..1be6ba7 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2019,8 +2019,6 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
int chars = 0;
unsigned long flags;
- int ret;
-
if (edge_port == NULL)
return 0;
@@ -2028,16 +2026,22 @@ static int edge_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&edge_port->write_fifo);
spin_unlock_irqrestore(&edge_port->ep_lock, flags);
- if (!chars) {
- ret = tx_active(edge_port);
- if (ret > 0)
- chars = ret;
- }
-
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
+static bool edge_tx_empty(struct usb_serial_port *port)
+{
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+ int ret;
+
+ ret = tx_active(edge_port);
+ if (ret > 0)
+ return false;
+
+ return true;
+}
+
static void edge_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
@@ -2557,6 +2561,7 @@ static struct usb_serial_driver edgeport_1port_device = {
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
+ .tx_empty = edge_tx_empty,
.break_ctl = edge_break,
.read_int_callback = edge_interrupt_callback,
.read_bulk_callback = edge_bulk_in_callback,
@@ -2589,6 +2594,7 @@ static struct usb_serial_driver edgeport_2port_device = {
.write = edge_write,
.write_room = edge_write_room,
.chars_in_buffer = edge_chars_in_buffer,
+ .tx_empty = edge_tx_empty,
.break_ctl = edge_break,
.read_int_callback = edge_interrupt_callback,
.read_bulk_callback = edge_bulk_in_callback,
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 9d74c27..790673e 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -287,7 +287,7 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
usb_bulk_msg(serial->dev,
usb_sndbulkpipe(serial->dev,
port->bulk_out_endpointAddress), buf,
- count, &actual, HZ * 1);
+ count, &actual, 1000);
if (status != IUU_OPERATION_OK)
dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status);
@@ -307,7 +307,7 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
usb_bulk_msg(serial->dev,
usb_rcvbulkpipe(serial->dev,
port->bulk_in_endpointAddress), buf,
- count, &actual, HZ * 1);
+ count, &actual, 1000);
if (status != IUU_OPERATION_OK)
dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status);
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index eb30d7b..3549d07 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1548,7 +1548,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
- int outcont_urb;
struct urb *this_urb;
int device_port, err;
@@ -1559,7 +1558,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
d_details = s_priv->device_details;
device_port = port->number - port->serial->minor;
- outcont_urb = d_details->outcont_endpoints[port->number];
this_urb = p_priv->outcont_urb;
dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe));
@@ -1685,14 +1683,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err != 0)
dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err);
-#if 0
- else {
- dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__
- outcont_urb, this_urb->transfer_buffer_length,
- usb_pipeendpoint(this_urb->pipe));
- }
-#endif
-
return 0;
}
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index cc0e543..f27c621 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -40,7 +40,7 @@
#define DRIVER_DESC "Moschip USB Serial Driver"
/* default urb timeout */
-#define MOS_WDR_TIMEOUT (HZ * 5)
+#define MOS_WDR_TIMEOUT 5000
#define MOS_MAX_PORT 0x02
#define MOS_WRITE 0x0E
@@ -227,11 +227,22 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,
__u8 requesttype = (__u8)0xc0;
__u16 index = get_reg_index(reg);
__u16 value = get_reg_value(reg, serial_portnum);
- int status = usb_control_msg(usbdev, pipe, request, requesttype, value,
- index, data, 1, MOS_WDR_TIMEOUT);
- if (status < 0)
+ u8 *buf;
+ int status;
+
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ status = usb_control_msg(usbdev, pipe, request, requesttype, value,
+ index, buf, 1, MOS_WDR_TIMEOUT);
+ if (status == 1)
+ *data = *buf;
+ else if (status < 0)
dev_err(&usbdev->dev,
"mos7720: usb_control_msg() failed: %d", status);
+ kfree(buf);
+
return status;
}
@@ -1618,7 +1629,7 @@ static void change_port_settings(struct tty_struct *tty,
mos7720_port->shadowMCR |= (UART_MCR_XONANY);
/* To set hardware flow control to the specified *
* serial port, in SP1/2_CONTROL_REG */
- if (port->number)
+ if (port_number)
write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x01);
else
write_mos_reg(serial, dummy, SP_CONTROL_REG, 0x02);
@@ -1927,7 +1938,7 @@ static int mos7720_startup(struct usb_serial *serial)
/* setting configuration feature to one */
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5*HZ);
+ (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000);
/* start the interrupt urb */
ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL);
@@ -1970,7 +1981,7 @@ static void mos7720_release(struct usb_serial *serial)
/* wait for synchronous usb calls to return */
if (mos_parport->msg_pending)
wait_for_completion_timeout(&mos_parport->syncmsg_compl,
- MOS_WDR_TIMEOUT);
+ msecs_to_jiffies(MOS_WDR_TIMEOUT));
parport_remove_port(mos_parport->pp);
usb_set_serial_data(serial, NULL);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index a0d5ea5..7e99808 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -2142,13 +2142,21 @@ static int mos7840_ioctl(struct tty_struct *tty,
static int mos7810_check(struct usb_serial *serial)
{
int i, pass_count = 0;
+ u8 *buf;
__u16 data = 0, mcr_data = 0;
__u16 test_pattern = 0x55AA;
+ int res;
+
+ buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
+ if (!buf)
+ return 0; /* failed to identify 7810 */
/* Store MCR setting */
- usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER,
- &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ if (res == VENDOR_READ_LENGTH)
+ mcr_data = *buf;
for (i = 0; i < 16; i++) {
/* Send the 1-bit test pattern out to MCS7810 test pin */
@@ -2158,9 +2166,12 @@ static int mos7810_check(struct usb_serial *serial)
MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT);
/* Read the test pattern back */
- usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
- VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ res = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
+ VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ if (res == VENDOR_READ_LENGTH)
+ data = *buf;
/* If this is a MCS7810 device, both test patterns must match */
if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001)
@@ -2174,6 +2185,8 @@ static int mos7810_check(struct usb_serial *serial)
MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL,
0, MOS_WDR_TIMEOUT);
+ kfree(buf);
+
if (pass_count == 16)
return 1;
@@ -2183,11 +2196,17 @@ static int mos7810_check(struct usb_serial *serial)
static int mos7840_calc_num_ports(struct usb_serial *serial)
{
__u16 data = 0x00;
+ u8 *buf;
int mos7840_num_ports;
- usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
- VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
+ if (buf) {
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
+ VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+ data = *buf;
+ kfree(buf);
+ }
if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 7343728..bd4323d 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -196,6 +196,7 @@ static void option_instat_callback(struct urb *urb);
#define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */
#define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */
+#define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */
#define KYOCERA_VENDOR_ID 0x0c88
#define KYOCERA_PRODUCT_KPC650 0x17da
@@ -249,13 +250,7 @@ static void option_instat_callback(struct urb *urb);
#define ZTE_PRODUCT_MF622 0x0001
#define ZTE_PRODUCT_MF628 0x0015
#define ZTE_PRODUCT_MF626 0x0031
-#define ZTE_PRODUCT_CDMA_TECH 0xfffe
-#define ZTE_PRODUCT_AC8710 0xfff1
-#define ZTE_PRODUCT_AC2726 0xfff5
-#define ZTE_PRODUCT_AC8710T 0xffff
#define ZTE_PRODUCT_MC2718 0xffe8
-#define ZTE_PRODUCT_AD3812 0xffeb
-#define ZTE_PRODUCT_MC2716 0xffed
#define BENQ_VENDOR_ID 0x04a5
#define BENQ_PRODUCT_H10 0x4068
@@ -341,8 +336,8 @@ static void option_instat_callback(struct urb *urb);
#define CINTERION_PRODUCT_EU3_E 0x0051
#define CINTERION_PRODUCT_EU3_P 0x0052
#define CINTERION_PRODUCT_PH8 0x0053
-#define CINTERION_PRODUCT_AH6 0x0055
-#define CINTERION_PRODUCT_PLS8 0x0060
+#define CINTERION_PRODUCT_AHXX 0x0055
+#define CINTERION_PRODUCT_PLXX 0x0060
/* Olivetti products */
#define OLIVETTI_VENDOR_ID 0x0b3c
@@ -494,18 +489,10 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = {
.reserved = BIT(4),
};
-static const struct option_blacklist_info zte_ad3812_z_blacklist = {
- .sendsetup = BIT(0) | BIT(1) | BIT(2),
-};
-
static const struct option_blacklist_info zte_mc2718_z_blacklist = {
.sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4),
};
-static const struct option_blacklist_info zte_mc2716_z_blacklist = {
- .sendsetup = BIT(1) | BIT(2) | BIT(3),
-};
-
static const struct option_blacklist_info huawei_cdc12_blacklist = {
.reserved = BIT(1) | BIT(2),
};
@@ -592,6 +579,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x14ac, 0xff, 0xff, 0xff), /* Huawei E1820 */
+ .driver_info = (kernel_ulong_t) &net_intf1_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) },
@@ -771,6 +760,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */
{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
@@ -795,7 +785,6 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_1012, 0xff) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) },
- { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */
@@ -966,6 +955,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0330, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0395, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0412, 0xff, 0xff, 0xff), /* Telewell TW-LTE 4G */
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0414, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0417, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
@@ -1195,16 +1186,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf3_blacklist },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) },
+ /* NOTE: most ZTE CDMA devices should be driven by zte_ev, not option */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff),
- .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) },
{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) },
@@ -1264,8 +1248,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) },
- { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AH6) },
- { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLS8) },
+ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
+ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 7151659..048cd44 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -284,7 +284,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
serial settings even to the same values as before. Thus
we actually need to filter in this specific case */
- if (!tty_termios_hw_change(&tty->termios, old_termios))
+ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
cflag = tty->termios.c_cflag;
@@ -293,7 +293,8 @@ static void pl2303_set_termios(struct tty_struct *tty,
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __func__);
/* Report back no change occurred */
- tty->termios = *old_termios;
+ if (old_termios)
+ tty->termios = *old_termios;
return;
}
@@ -433,7 +434,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
control = priv->line_control;
if ((cflag & CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
- else if ((old_termios->c_cflag & CBAUD) == B0)
+ else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
if (control != priv->line_control) {
control = priv->line_control;
@@ -492,7 +493,6 @@ static void pl2303_close(struct usb_serial_port *port)
static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct pl2303_serial_private *spriv = usb_get_serial_data(serial);
int result;
@@ -508,7 +508,7 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
/* Setup termios */
if (tty)
- pl2303_set_termios(tty, port, &tmp_termios);
+ pl2303_set_termios(tty, port, NULL);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 59b32b7..bd794b4 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -118,6 +118,7 @@ static const struct usb_device_id id_table[] = {
{USB_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */
{USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */
{USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */
+ {USB_DEVICE(0x0AF0, 0x8120)}, /* Option GTM681W */
/* non Gobi Qualcomm serial devices */
{USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 0)}, /* Sierra Wireless MC7700 Device Management */
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index cf3df79..ddf6c47 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -291,7 +291,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
unsigned int cflag = tty->termios.c_cflag;
- unsigned int old_cflag = old_termios->c_cflag;
unsigned short uartdata;
unsigned char buf[2] = {0, 0};
int baud;
@@ -299,15 +298,15 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
u8 control;
/* check that they really want us to change something */
- if (!tty_termios_hw_change(&tty->termios, old_termios))
+ if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
return;
/* set DTR/RTS active */
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
- if ((old_cflag & CBAUD) == B0) {
+ if (old_termios && (old_termios->c_cflag & CBAUD) == B0) {
priv->line_control |= MCR_DTR;
- if (!(old_cflag & CRTSCTS))
+ if (!(old_termios->c_cflag & CRTSCTS))
priv->line_control |= MCR_RTS;
}
if (control != priv->line_control) {
@@ -394,7 +393,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct spcp8x5_private *priv = usb_get_serial_port_data(port);
int ret;
@@ -411,7 +409,7 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
spcp8x5_set_ctrl_line(port, priv->line_control);
if (tty)
- spcp8x5_set_termios(tty, port, &tmp_termios);
+ spcp8x5_set_termios(tty, port, NULL);
port->port.drain_delay = 256;
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index cac47ae..c92c5ed 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -101,6 +101,7 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *data, int count);
static int ti_write_room(struct tty_struct *tty);
static int ti_chars_in_buffer(struct tty_struct *tty);
+static bool ti_tx_empty(struct usb_serial_port *port);
static void ti_throttle(struct tty_struct *tty);
static void ti_unthrottle(struct tty_struct *tty);
static int ti_ioctl(struct tty_struct *tty,
@@ -222,6 +223,7 @@ static struct usb_serial_driver ti_1port_device = {
.write = ti_write,
.write_room = ti_write_room,
.chars_in_buffer = ti_chars_in_buffer,
+ .tx_empty = ti_tx_empty,
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
.ioctl = ti_ioctl,
@@ -253,6 +255,7 @@ static struct usb_serial_driver ti_2port_device = {
.write = ti_write,
.write_room = ti_write_room,
.chars_in_buffer = ti_chars_in_buffer,
+ .tx_empty = ti_tx_empty,
.throttle = ti_throttle,
.unthrottle = ti_unthrottle,
.ioctl = ti_ioctl,
@@ -684,8 +687,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
struct ti_port *tport = usb_get_serial_port_data(port);
int chars = 0;
unsigned long flags;
- int ret;
- u8 lsr;
if (tport == NULL)
return 0;
@@ -694,16 +695,22 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&tport->write_fifo);
spin_unlock_irqrestore(&tport->tp_lock, flags);
- if (!chars) {
- ret = ti_get_lsr(tport, &lsr);
- if (!ret && !(lsr & TI_LSR_TX_EMPTY))
- chars = 1;
- }
-
dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
+static bool ti_tx_empty(struct usb_serial_port *port)
+{
+ struct ti_port *tport = usb_get_serial_port_data(port);
+ int ret;
+ u8 lsr;
+
+ ret = ti_get_lsr(tport, &lsr);
+ if (!ret && !(lsr & TI_LSR_TX_EMPTY))
+ return false;
+
+ return true;
+}
static void ti_throttle(struct tty_struct *tty)
{
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index cf75beb..5f6b1ff 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -359,20 +359,29 @@ static int serial_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
- int count = 0;
dev_dbg(tty->dev, "%s\n", __func__);
- mutex_lock(&serial->disc_mutex);
- /* if the device was unplugged then any remaining characters
- fell out of the connector ;) */
if (serial->disconnected)
- count = 0;
- else
- count = serial->type->chars_in_buffer(tty);
- mutex_unlock(&serial->disc_mutex);
+ return 0;
- return count;
+ return serial->type->chars_in_buffer(tty);
+}
+
+static void serial_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+
+ dev_dbg(tty->dev, "%s\n", __func__);
+
+ if (!port->serial->type->wait_until_sent)
+ return;
+
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ port->serial->type->wait_until_sent(tty, timeout);
+ mutex_unlock(&serial->disc_mutex);
}
static void serial_throttle(struct tty_struct *tty)
@@ -399,7 +408,7 @@ static int serial_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
+ int retval = -ENOIOCTLCMD;
dev_dbg(tty->dev, "%s - cmd 0x%.4x\n", __func__, cmd);
@@ -411,8 +420,6 @@ static int serial_ioctl(struct tty_struct *tty,
default:
if (port->serial->type->ioctl)
retval = port->serial->type->ioctl(tty, cmd, arg);
- else
- retval = -ENOIOCTLCMD;
}
return retval;
@@ -1191,6 +1198,7 @@ static const struct tty_operations serial_ops = {
.unthrottle = serial_unthrottle,
.break_ctl = serial_break,
.chars_in_buffer = serial_chars_in_buffer,
+ .wait_until_sent = serial_wait_until_sent,
.tiocmget = serial_tiocmget,
.tiocmset = serial_tiocmset,
.get_icount = serial_get_icount,
@@ -1316,6 +1324,8 @@ static void usb_serial_operations_init(struct usb_serial_driver *device)
set_to_generic_if_null(device, close);
set_to_generic_if_null(device, write_room);
set_to_generic_if_null(device, chars_in_buffer);
+ if (device->tx_empty)
+ set_to_generic_if_null(device, wait_until_sent);
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
set_to_generic_if_null(device, process_read_urb);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 7573ec8..9910aa2 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -560,10 +560,19 @@ static int treo_attach(struct usb_serial *serial)
*/
#define COPY_PORT(dest, src) \
do { \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(src->read_urbs); ++i) { \
+ dest->read_urbs[i] = src->read_urbs[i]; \
+ dest->read_urbs[i]->context = dest; \
+ dest->bulk_in_buffers[i] = src->bulk_in_buffers[i]; \
+ } \
dest->read_urb = src->read_urb; \
dest->bulk_in_endpointAddress = src->bulk_in_endpointAddress;\
dest->bulk_in_buffer = src->bulk_in_buffer; \
+ dest->bulk_in_size = src->bulk_in_size; \
dest->interrupt_in_urb = src->interrupt_in_urb; \
+ dest->interrupt_in_urb->context = dest; \
dest->interrupt_in_endpointAddress = \
src->interrupt_in_endpointAddress;\
dest->interrupt_in_buffer = src->interrupt_in_buffer; \
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index b9fca35..347caad 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -649,7 +649,7 @@ static void firm_setup_port(struct tty_struct *tty)
struct whiteheat_port_settings port_settings;
unsigned int cflag = tty->termios.c_cflag;
- port_settings.port = port->number + 1;
+ port_settings.port = port->number - port->serial->minor + 1;
/* get the byte size */
switch (cflag & CSIZE) {
diff --git a/drivers/usb/serial/zte_ev.c b/drivers/usb/serial/zte_ev.c
index 39ee737..fca4c75 100644
--- a/drivers/usb/serial/zte_ev.c
+++ b/drivers/usb/serial/zte_ev.c
@@ -41,9 +41,6 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
int len;
unsigned char *buf;
- if (port->number != 0)
- return -ENODEV;
-
buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -53,7 +50,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0001, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
/* send 2st cmd and recieve data */
@@ -65,7 +62,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x21, 0xa1,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
/* send 3 cmd */
@@ -84,7 +81,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x20, 0x21,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
/* send 4 cmd */
@@ -95,7 +92,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0003, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
/* send 5 cmd */
@@ -107,7 +104,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x21, 0xa1,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
/* send 6 cmd */
@@ -126,7 +123,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x20, 0x21,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
kfree(buf);
@@ -166,9 +163,6 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
int len;
unsigned char *buf;
- if (port->number != 0)
- return;
-
buf = kmalloc(MAX_SETUP_DATA_SIZE, GFP_KERNEL);
if (!buf)
return;
@@ -178,7 +172,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0002, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
/* send 2st ctl cmd(CTL 21 22 03 00 00 00 00 00 ) */
@@ -186,7 +180,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0003, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
/* send 3st cmd and recieve data */
@@ -198,7 +192,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x21, 0xa1,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
/* send 4 cmd */
@@ -217,7 +211,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x20, 0x21,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
/* send 5 cmd */
@@ -228,7 +222,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0003, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
/* send 6 cmd */
@@ -240,7 +234,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0x21, 0xa1,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
/* send 7 cmd */
@@ -259,7 +253,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x20, 0x21,
0x0000, 0x0000, buf, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
debug_data(dev, __func__, len, buf, result);
/* send 8 cmd */
@@ -270,7 +264,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
0x22, 0x21,
0x0003, 0x0000, NULL, len,
- HZ * USB_CTRL_GET_TIMEOUT);
+ USB_CTRL_GET_TIMEOUT);
dev_dbg(dev, "result = %d\n", result);
kfree(buf);
@@ -279,11 +273,29 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)
}
static const struct usb_device_id id_table[] = {
- { USB_DEVICE(0x19d2, 0xffff) }, /* AC8700 */
- { USB_DEVICE(0x19d2, 0xfffe) },
- { USB_DEVICE(0x19d2, 0xfffd) }, /* MG880 */
+ /* AC8710, AC8710T */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffff, 0xff, 0xff, 0xff) },
+ /* AC8700 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfffe, 0xff, 0xff, 0xff) },
+ /* MG880 */
+ { USB_DEVICE(0x19d2, 0xfffd) },
+ { USB_DEVICE(0x19d2, 0xfffc) },
+ { USB_DEVICE(0x19d2, 0xfffb) },
+ /* AC2726, AC8710_V3 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfff1, 0xff, 0xff, 0xff) },
+ { USB_DEVICE(0x19d2, 0xfff6) },
+ { USB_DEVICE(0x19d2, 0xfff7) },
+ { USB_DEVICE(0x19d2, 0xfff8) },
+ { USB_DEVICE(0x19d2, 0xfff9) },
+ { USB_DEVICE(0x19d2, 0xffee) },
+ /* AC2716, MC2716 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffed, 0xff, 0xff, 0xff) },
+ /* AD3812 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xffeb, 0xff, 0xff, 0xff) },
+ { USB_DEVICE(0x19d2, 0xffec) },
{ USB_DEVICE(0x05C6, 0x3197) },
{ USB_DEVICE(0x05C6, 0x6000) },
+ { USB_DEVICE(0x05C6, 0x9008) },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index 8623577..281be56 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -105,8 +105,9 @@ struct rts51x_chip {
int status_len;
u32 flag;
-#ifdef CONFIG_REALTEK_AUTOPM
struct us_data *us;
+
+#ifdef CONFIG_REALTEK_AUTOPM
struct timer_list rts51x_suspend_timer;
unsigned long timer_expires;
int pwr_state;
@@ -988,6 +989,7 @@ static int init_realtek_cr(struct us_data *us)
us->extra = chip;
us->extra_destructor = realtek_cr_destructor;
us->max_lun = chip->max_lun = rts51x_get_max_lun(us);
+ chip->us = us;
usb_stor_dbg(us, "chip->max_lun = %d\n", chip->max_lun);
@@ -1010,10 +1012,8 @@ static int init_realtek_cr(struct us_data *us)
SET_AUTO_DELINK(chip);
}
#ifdef CONFIG_REALTEK_AUTOPM
- if (ss_en) {
- chip->us = us;
+ if (ss_en)
realtek_cr_autosuspend_setup(us);
- }
#endif
usb_stor_dbg(us, "chip->flag = 0x%x\n", chip->flag);
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index acb7121..6d78736 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -1360,7 +1360,7 @@ static const struct file_operations vfio_device_fops = {
*/
static char *vfio_devnode(struct device *dev, umode_t *mode)
{
- if (MINOR(dev->devt) == 0)
+ if (mode && (MINOR(dev->devt) == 0))
*mode = S_IRUGO | S_IWUGO;
return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev));
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 2b51e23..f80d3dd 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -155,14 +155,11 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs)
static void vhost_net_clear_ubuf_info(struct vhost_net *n)
{
-
- bool zcopy;
int i;
- for (i = 0; i < n->dev.nvqs; ++i) {
- zcopy = vhost_net_zcopy_mask & (0x1 << i);
- if (zcopy)
- kfree(n->vqs[i].ubuf_info);
+ for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
+ kfree(n->vqs[i].ubuf_info);
+ n->vqs[i].ubuf_info = NULL;
}
}
@@ -171,7 +168,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n)
bool zcopy;
int i;
- for (i = 0; i < n->dev.nvqs; ++i) {
+ for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
zcopy = vhost_net_zcopy_mask & (0x1 << i);
if (!zcopy)
continue;
@@ -183,12 +180,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n)
return 0;
err:
- while (i--) {
- zcopy = vhost_net_zcopy_mask & (0x1 << i);
- if (!zcopy)
- continue;
- kfree(n->vqs[i].ubuf_info);
- }
+ vhost_net_clear_ubuf_info(n);
return -ENOMEM;
}
@@ -196,12 +188,12 @@ void vhost_net_vq_reset(struct vhost_net *n)
{
int i;
+ vhost_net_clear_ubuf_info(n);
+
for (i = 0; i < VHOST_NET_VQ_MAX; i++) {
n->vqs[i].done_idx = 0;
n->vqs[i].upend_idx = 0;
n->vqs[i].ubufs = NULL;
- kfree(n->vqs[i].ubuf_info);
- n->vqs[i].ubuf_info = NULL;
n->vqs[i].vhost_hlen = 0;
n->vqs[i].sock_hlen = 0;
}
@@ -436,7 +428,8 @@ static void handle_tx(struct vhost_net *net)
kref_get(&ubufs->kref);
}
nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV;
- }
+ } else
+ msg.msg_control = NULL;
/* TODO: Check specific error and bomb out unless ENOBUFS? */
err = sock->ops->sendmsg(NULL, sock, &msg, len);
if (unlikely(err < 0)) {
@@ -1053,6 +1046,10 @@ static long vhost_net_set_owner(struct vhost_net *n)
int r;
mutex_lock(&n->dev.mutex);
+ if (vhost_dev_has_owner(&n->dev)) {
+ r = -EBUSY;
+ goto out;
+ }
r = vhost_net_set_ubuf_info(n);
if (r)
goto out;
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index beee7f5..60aa5ad 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -344,13 +344,19 @@ static int vhost_attach_cgroups(struct vhost_dev *dev)
}
/* Caller should have device mutex */
+bool vhost_dev_has_owner(struct vhost_dev *dev)
+{
+ return dev->mm;
+}
+
+/* Caller should have device mutex */
long vhost_dev_set_owner(struct vhost_dev *dev)
{
struct task_struct *worker;
int err;
/* Is there an owner already? */
- if (dev->mm) {
+ if (vhost_dev_has_owner(dev)) {
err = -EBUSY;
goto err_mm;
}
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index a7ad635..64adcf9 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -133,6 +133,7 @@ struct vhost_dev {
long vhost_dev_init(struct vhost_dev *, struct vhost_virtqueue **vqs, int nvqs);
long vhost_dev_set_owner(struct vhost_dev *dev);
+bool vhost_dev_has_owner(struct vhost_dev *dev);
long vhost_dev_check_owner(struct vhost_dev *);
struct vhost_memory *vhost_dev_reset_owner_prepare(void);
void vhost_dev_reset_owner(struct vhost_dev *, struct vhost_memory *);
diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
index bff0775..5174eba 100644
--- a/drivers/vhost/vringh.c
+++ b/drivers/vhost/vringh.c
@@ -3,6 +3,7 @@
*
* Since these may be in userspace, we use (inline) accessors.
*/
+#include <linux/module.h>
#include <linux/vringh.h>
#include <linux/virtio_ring.h>
#include <linux/kernel.h>
@@ -1005,3 +1006,5 @@ int vringh_need_notify_kern(struct vringh *vrh)
return __vringh_need_notify(vrh, getu16_kern);
}
EXPORT_SYMBOL(vringh_need_notify_kern);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d71d60f..2e937bd 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2199,7 +2199,7 @@ config FB_XILINX
config FB_GOLDFISH
tristate "Goldfish Framebuffer"
- depends on FB
+ depends on FB && HAS_DMA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -2453,6 +2453,23 @@ config FB_HYPERV
help
This framebuffer driver supports Microsoft Hyper-V Synthetic Video.
+config FB_SIMPLE
+ bool "Simple framebuffer support"
+ depends on (FB = y) && OF
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Say Y if you want support for a simple frame-buffer.
+
+ This driver assumes that the display hardware has been initialized
+ before the kernel boots, and the kernel will simply render to the
+ pre-allocated frame buffer surface.
+
+ Configuration re: surface address, size, and format must be provided
+ through device tree, or potentially plain old platform data in the
+ future.
+
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"
source "drivers/video/exynos/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 7234e4a..e8bae8d 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -166,6 +166,7 @@ obj-$(CONFIG_FB_MX3) += mx3fb.o
obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
obj-$(CONFIG_FB_MXS) += mxsfb.o
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
+obj-$(CONFIG_FB_SIMPLE) += simplefb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 540909d..effdb37 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -223,8 +223,14 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo)
static void exit_backlight(struct atmel_lcdfb_info *sinfo)
{
- if (sinfo->backlight)
- backlight_device_unregister(sinfo->backlight);
+ if (!sinfo->backlight)
+ return;
+
+ if (sinfo->backlight->ops) {
+ sinfo->backlight->props.power = FB_BLANK_POWERDOWN;
+ sinfo->backlight->ops->update_status(sinfo->backlight);
+ }
+ backlight_device_unregister(sinfo->backlight);
}
#else
@@ -461,8 +467,11 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
if (info->fix.smem_len) {
unsigned int smem_len = (var->xres_virtual * var->yres_virtual
* ((var->bits_per_pixel + 7) / 8));
- if (smem_len > info->fix.smem_len)
+ if (smem_len > info->fix.smem_len) {
+ dev_err(dev, "Frame buffer is too small (%u) for screen size (need at least %u)\n",
+ info->fix.smem_len, smem_len);
return -EINVAL;
+ }
}
/* Saturate vertical and horizontal timings at maximum values */
diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
index a862e91..48da25c 100644
--- a/drivers/video/console/Makefile
+++ b/drivers/video/console/Makefile
@@ -18,6 +18,8 @@ font-objs-$(CONFIG_FONT_MINI_4x6) += font_mini_4x6.o
font-objs += $(font-objs-y)
+obj-$(CONFIG_FONTS) += font.o
+
# Each configuration option enables a list of files.
obj-$(CONFIG_DUMMY_CONSOLE) += dummycon.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 60cc6fe..c9c2252 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -53,6 +53,8 @@ static char *def_disp_name;
module_param_named(def_disp, def_disp_name, charp, 0);
MODULE_PARM_DESC(def_disp, "default display name");
+static bool dss_initialized;
+
const char *omapdss_get_default_display_name(void)
{
return core.default_display_name;
@@ -66,6 +68,12 @@ enum omapdss_version omapdss_get_version(void)
}
EXPORT_SYMBOL(omapdss_get_version);
+bool omapdss_is_initialized(void)
+{
+ return dss_initialized;
+}
+EXPORT_SYMBOL(omapdss_is_initialized);
+
struct platform_device *dss_get_core_pdev(void)
{
return core.pdev;
@@ -603,6 +611,8 @@ static int __init omap_dss_init(void)
return r;
}
+ dss_initialized = true;
+
return 0;
}
@@ -633,7 +643,15 @@ static int __init omap_dss_init(void)
static int __init omap_dss_init2(void)
{
- return omap_dss_register_drivers();
+ int r;
+
+ r = omap_dss_register_drivers();
+ if (r)
+ return r;
+
+ dss_initialized = true;
+
+ return 0;
}
core_initcall(omap_dss_init);
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 17f4d55..a109934 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -1065,10 +1065,6 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
mutex_init(&hdmi.ip_data.lock);
res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0);
- if (!res) {
- DSSERR("can't get IORESOURCE_MEM HDMI\n");
- return -EINVAL;
- }
/* Base address taken from platform */
hdmi.ip_data.base_wp = devm_ioremap_resource(&pdev->dev, res);
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index c84bb8a..856917b 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -2416,6 +2416,9 @@ static int omapfb_probe(struct platform_device *pdev)
DBG("omapfb_probe\n");
+ if (omapdss_is_initialized() == false)
+ return -EPROBE_DEFER;
+
if (pdev->num_resources != 0) {
dev_err(&pdev->dev, "probed for an unknown device\n");
r = -ENODEV;
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
index 5261229..f346b02 100644
--- a/drivers/video/omap2/vrfb.c
+++ b/drivers/video/omap2/vrfb.c
@@ -353,11 +353,6 @@ static int __init vrfb_probe(struct platform_device *pdev)
/* first resource is the register res, the rest are vrfb contexts */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "can't get vrfb base address\n");
- return -EINVAL;
- }
-
vrfb_base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(vrfb_base))
return PTR_ERR(vrfb_base);
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index d9f08c6..dbfe2c1 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -710,7 +710,7 @@ static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
r = vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len);
dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n",
- info->fix.smem_start + vma->vm_pgoff << PAGE_SHIFT,
+ info->fix.smem_start + (vma->vm_pgoff << PAGE_SHIFT),
vma->vm_start);
return r;
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c
new file mode 100644
index 0000000..e2e9e3e
--- /dev/null
+++ b/drivers/video/simplefb.c
@@ -0,0 +1,234 @@
+/*
+ * Simplest possible simple frame-buffer driver, as a platform device
+ *
+ * Copyright (c) 2013, Stephen Warren
+ *
+ * Based on q40fb.c, which was:
+ * Copyright (C) 2001 Richard Zidlicky <rz@linux-m68k.org>
+ *
+ * Also based on offb.c, which was:
+ * Copyright (C) 1997 Geert Uytterhoeven
+ * Copyright (C) 1996 Paul Mackerras
+ *
+ * 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.
+ */
+
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+static struct fb_fix_screeninfo simplefb_fix = {
+ .id = "simple",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .accel = FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo simplefb_var = {
+ .height = -1,
+ .width = -1,
+ .activate = FB_ACTIVATE_NOW,
+ .vmode = FB_VMODE_NONINTERLACED,
+};
+
+static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ u32 *pal = info->pseudo_palette;
+ u32 cr = red >> (16 - info->var.red.length);
+ u32 cg = green >> (16 - info->var.green.length);
+ u32 cb = blue >> (16 - info->var.blue.length);
+ u32 value;
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ value = (cr << info->var.red.offset) |
+ (cg << info->var.green.offset) |
+ (cb << info->var.blue.offset);
+ if (info->var.transp.length > 0) {
+ u32 mask = (1 << info->var.transp.length) - 1;
+ mask <<= info->var.transp.offset;
+ value |= mask;
+ }
+ pal[regno] = value;
+
+ return 0;
+}
+
+static struct fb_ops simplefb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = simplefb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+struct simplefb_format {
+ const char *name;
+ u32 bits_per_pixel;
+ struct fb_bitfield red;
+ struct fb_bitfield green;
+ struct fb_bitfield blue;
+ struct fb_bitfield transp;
+};
+
+static struct simplefb_format simplefb_formats[] = {
+ { "r5g6b5", 16, {11, 5}, {5, 6}, {0, 5}, {0, 0} },
+};
+
+struct simplefb_params {
+ u32 width;
+ u32 height;
+ u32 stride;
+ struct simplefb_format *format;
+};
+
+static int simplefb_parse_dt(struct platform_device *pdev,
+ struct simplefb_params *params)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
+ const char *format;
+ int i;
+
+ ret = of_property_read_u32(np, "width", &params->width);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't parse width property\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "height", &params->height);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't parse height property\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(np, "stride", &params->stride);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't parse stride property\n");
+ return ret;
+ }
+
+ ret = of_property_read_string(np, "format", &format);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't parse format property\n");
+ return ret;
+ }
+ params->format = NULL;
+ for (i = 0; i < ARRAY_SIZE(simplefb_formats); i++) {
+ if (strcmp(format, simplefb_formats[i].name))
+ continue;
+ params->format = &simplefb_formats[i];
+ break;
+ }
+ if (!params->format) {
+ dev_err(&pdev->dev, "Invalid format value\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int simplefb_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct simplefb_params params;
+ struct fb_info *info;
+ struct resource *mem;
+
+ if (fb_get_options("simplefb", NULL))
+ return -ENODEV;
+
+ ret = simplefb_parse_dt(pdev, &params);
+ if (ret)
+ return ret;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ return -EINVAL;
+ }
+
+ info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
+ if (!info)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, info);
+
+ info->fix = simplefb_fix;
+ info->fix.smem_start = mem->start;
+ info->fix.smem_len = resource_size(mem);
+ info->fix.line_length = params.stride;
+
+ info->var = simplefb_var;
+ info->var.xres = params.width;
+ info->var.yres = params.height;
+ info->var.xres_virtual = params.width;
+ info->var.yres_virtual = params.height;
+ info->var.bits_per_pixel = params.format->bits_per_pixel;
+ info->var.red = params.format->red;
+ info->var.green = params.format->green;
+ info->var.blue = params.format->blue;
+ info->var.transp = params.format->transp;
+
+ info->fbops = &simplefb_ops;
+ info->flags = FBINFO_DEFAULT;
+ info->screen_base = devm_ioremap(&pdev->dev, info->fix.smem_start,
+ info->fix.smem_len);
+ if (!info->screen_base) {
+ framebuffer_release(info);
+ return -ENODEV;
+ }
+ info->pseudo_palette = (void *)(info + 1);
+
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
+ framebuffer_release(info);
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
+
+ return 0;
+}
+
+static int simplefb_remove(struct platform_device *pdev)
+{
+ struct fb_info *info = platform_get_drvdata(pdev);
+
+ unregister_framebuffer(info);
+ framebuffer_release(info);
+
+ return 0;
+}
+
+static const struct of_device_id simplefb_of_match[] = {
+ { .compatible = "simple-framebuffer", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, simplefb_of_match);
+
+static struct platform_driver simplefb_driver = {
+ .driver = {
+ .name = "simple-framebuffer",
+ .owner = THIS_MODULE,
+ .of_match_table = simplefb_of_match,
+ },
+ .probe = simplefb_probe,
+ .remove = simplefb_remove,
+};
+module_platform_driver(simplefb_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
+MODULE_DESCRIPTION("Simple framebuffer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index db2390a..6e94d8dd 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -555,11 +555,6 @@ static int omap_hdq_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hdq_data);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_dbg(&pdev->dev, "unable to get resource\n");
- return -ENXIO;
- }
-
hdq_data->hdq_base = devm_ioremap_resource(dev, res);
if (IS_ERR(hdq_data->hdq_base))
return PTR_ERR(hdq_data->hdq_base);
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index d184c48..37cb09b 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -248,11 +248,6 @@ static int ath79_wdt_probe(struct platform_device *pdev)
return -EBUSY;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "no memory resource found\n");
- return -EINVAL;
- }
-
wdt_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(wdt_base))
return PTR_ERR(wdt_base);
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index 100d4fb..bead774 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -217,11 +217,6 @@ static int davinci_wdt_probe(struct platform_device *pdev)
dev_info(dev, "heartbeat %d sec\n", heartbeat);
wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (wdt_mem == NULL) {
- dev_err(dev, "failed to get memory region resource\n");
- return -ENOENT;
- }
-
wdt_base = devm_ioremap_resource(dev, wdt_mem);
if (IS_ERR(wdt_base))
return PTR_ERR(wdt_base);
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index ff90882..62946c2 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -257,11 +257,6 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "can't get device resources\n");
- return -ENODEV;
- }
-
imx2_wdt.base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(imx2_wdt.base))
return PTR_ERR(imx2_wdt.base);
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index f03bf50..9e02d60 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -19,11 +19,10 @@ config XEN_SELFBALLOONING
by the current usage of anonymous memory ("committed AS") and
controlled by various sysfs-settable parameters. Configuring
FRONTSWAP is highly recommended; if it is not configured, self-
- ballooning is disabled by default but can be enabled with the
- 'selfballooning' kernel boot parameter. If FRONTSWAP is configured,
+ ballooning is disabled by default. If FRONTSWAP is configured,
frontswap-selfshrinking is enabled by default but can be disabled
- with the 'noselfshrink' kernel boot parameter; and self-ballooning
- is enabled by default but can be disabled with the 'noselfballooning'
+ with the 'tmem.selfshrink=0' kernel boot parameter; and self-ballooning
+ is enabled by default but can be disabled with the 'tmem.selfballooning=0'
kernel boot parameter. Note that systems without a sufficiently
large swap device should not enable self-ballooning.
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index a56776d..930fb68 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -407,7 +407,8 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
nr_pages = ARRAY_SIZE(frame_list);
for (i = 0; i < nr_pages; i++) {
- if ((page = alloc_page(gfp)) == NULL) {
+ page = alloc_page(gfp);
+ if (page == NULL) {
nr_pages = i;
state = BP_EAGAIN;
break;
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index ca2b00e..2cfc24d 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -504,7 +504,7 @@ static void privcmd_close(struct vm_area_struct *vma)
struct page **pages = vma->vm_private_data;
int numpgs = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
- if (!xen_feature(XENFEAT_auto_translated_physmap || !numpgs || !pages))
+ if (!xen_feature(XENFEAT_auto_translated_physmap) || !numpgs || !pages)
return;
xen_unmap_domain_mfn_range(vma, numpgs, pages);
diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c
index e3600be..0f0493c 100644
--- a/drivers/xen/tmem.c
+++ b/drivers/xen/tmem.c
@@ -11,11 +11,7 @@
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/cleancache.h>
-
-/* temporary ifdef until include/linux/frontswap.h is upstream */
-#ifdef CONFIG_FRONTSWAP
#include <linux/frontswap.h>
-#endif
#include <xen/xen.h>
#include <xen/interface/xen.h>
@@ -24,6 +20,36 @@
#include <asm/xen/hypervisor.h>
#include <xen/tmem.h>
+#ifndef CONFIG_XEN_TMEM_MODULE
+bool __read_mostly tmem_enabled = false;
+
+static int __init enable_tmem(char *s)
+{
+ tmem_enabled = true;
+ return 1;
+}
+__setup("tmem", enable_tmem);
+#endif
+
+#ifdef CONFIG_CLEANCACHE
+static bool cleancache __read_mostly = true;
+module_param(cleancache, bool, S_IRUGO);
+static bool selfballooning __read_mostly = true;
+module_param(selfballooning, bool, S_IRUGO);
+#endif /* CONFIG_CLEANCACHE */
+
+#ifdef CONFIG_FRONTSWAP
+static bool frontswap __read_mostly = true;
+module_param(frontswap, bool, S_IRUGO);
+#else /* CONFIG_FRONTSWAP */
+#define frontswap (0)
+#endif /* CONFIG_FRONTSWAP */
+
+#ifdef CONFIG_XEN_SELFBALLOONING
+static bool selfshrinking __read_mostly = true;
+module_param(selfshrinking, bool, S_IRUGO);
+#endif /* CONFIG_XEN_SELFBALLOONING */
+
#define TMEM_CONTROL 0
#define TMEM_NEW_POOL 1
#define TMEM_DESTROY_POOL 2
@@ -129,16 +155,6 @@ static int xen_tmem_flush_object(u32 pool_id, struct tmem_oid oid)
return xen_tmem_op(TMEM_FLUSH_OBJECT, pool_id, oid, 0, 0, 0, 0, 0);
}
-#ifndef CONFIG_XEN_TMEM_MODULE
-bool __read_mostly tmem_enabled = false;
-
-static int __init enable_tmem(char *s)
-{
- tmem_enabled = true;
- return 1;
-}
-__setup("tmem", enable_tmem);
-#endif
#ifdef CONFIG_CLEANCACHE
static int xen_tmem_destroy_pool(u32 pool_id)
@@ -230,20 +246,6 @@ static int tmem_cleancache_init_shared_fs(char *uuid, size_t pagesize)
return xen_tmem_new_pool(shared_uuid, TMEM_POOL_SHARED, pagesize);
}
-static bool disable_cleancache __read_mostly;
-static bool disable_selfballooning __read_mostly;
-#ifdef CONFIG_XEN_TMEM_MODULE
-module_param(disable_cleancache, bool, S_IRUGO);
-module_param(disable_selfballooning, bool, S_IRUGO);
-#else
-static int __init no_cleancache(char *s)
-{
- disable_cleancache = true;
- return 1;
-}
-__setup("nocleancache", no_cleancache);
-#endif
-
static struct cleancache_ops tmem_cleancache_ops = {
.put_page = tmem_cleancache_put_page,
.get_page = tmem_cleancache_get_page,
@@ -361,20 +363,6 @@ static void tmem_frontswap_init(unsigned ignored)
xen_tmem_new_pool(private, TMEM_POOL_PERSIST, PAGE_SIZE);
}
-static bool disable_frontswap __read_mostly;
-static bool disable_frontswap_selfshrinking __read_mostly;
-#ifdef CONFIG_XEN_TMEM_MODULE
-module_param(disable_frontswap, bool, S_IRUGO);
-module_param(disable_frontswap_selfshrinking, bool, S_IRUGO);
-#else
-static int __init no_frontswap(char *s)
-{
- disable_frontswap = true;
- return 1;
-}
-__setup("nofrontswap", no_frontswap);
-#endif
-
static struct frontswap_ops tmem_frontswap_ops = {
.store = tmem_frontswap_store,
.load = tmem_frontswap_load,
@@ -382,8 +370,6 @@ static struct frontswap_ops tmem_frontswap_ops = {
.invalidate_area = tmem_frontswap_flush_area,
.init = tmem_frontswap_init
};
-#else /* CONFIG_FRONTSWAP */
-#define disable_frontswap_selfshrinking 1
#endif
static int xen_tmem_init(void)
@@ -391,12 +377,12 @@ static int xen_tmem_init(void)
if (!xen_domain())
return 0;
#ifdef CONFIG_FRONTSWAP
- if (tmem_enabled && !disable_frontswap) {
+ if (tmem_enabled && frontswap) {
char *s = "";
- struct frontswap_ops *old_ops =
- frontswap_register_ops(&tmem_frontswap_ops);
+ struct frontswap_ops *old_ops;
tmem_frontswap_poolid = -1;
+ old_ops = frontswap_register_ops(&tmem_frontswap_ops);
if (IS_ERR(old_ops) || old_ops) {
if (IS_ERR(old_ops))
return PTR_ERR(old_ops);
@@ -408,7 +394,7 @@ static int xen_tmem_init(void)
#endif
#ifdef CONFIG_CLEANCACHE
BUG_ON(sizeof(struct cleancache_filekey) != sizeof(struct tmem_oid));
- if (tmem_enabled && !disable_cleancache) {
+ if (tmem_enabled && cleancache) {
char *s = "";
struct cleancache_ops *old_ops =
cleancache_register_ops(&tmem_cleancache_ops);
@@ -419,8 +405,15 @@ static int xen_tmem_init(void)
}
#endif
#ifdef CONFIG_XEN_SELFBALLOONING
- xen_selfballoon_init(!disable_selfballooning,
- !disable_frontswap_selfshrinking);
+ /*
+ * There is no point of driving pages to the swap system if they
+ * aren't going anywhere in tmem universe.
+ */
+ if (!frontswap) {
+ selfshrinking = false;
+ selfballooning = false;
+ }
+ xen_selfballoon_init(selfballooning, selfshrinking);
#endif
return 0;
}
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index a2278ba..4e8ba38 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -106,7 +106,7 @@ static void pcistub_device_release(struct kref *kref)
else
pci_restore_state(dev);
- if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) {
+ if (dev->msix_cap) {
struct physdev_pci_device ppdev = {
.seg = pci_domain_nr(dev->bus),
.bus = dev->bus->number,
@@ -371,7 +371,7 @@ static int pcistub_init_device(struct pci_dev *dev)
if (err)
goto config_release;
- if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) {
+ if (dev->msix_cap) {
struct physdev_pci_device ppdev = {
.seg = pci_domain_nr(dev->bus),
.bus = dev->bus->number,
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c
index f2ef569..f70984a8 100644
--- a/drivers/xen/xen-selfballoon.c
+++ b/drivers/xen/xen-selfballoon.c
@@ -53,15 +53,12 @@
* System configuration note: Selfballooning should not be enabled on
* systems without a sufficiently large swap device configured; for best
* results, it is recommended that total swap be increased by the size
- * of the guest memory. Also, while technically not required to be
- * configured, it is highly recommended that frontswap also be configured
- * and enabled when selfballooning is running. So, selfballooning
- * is disabled by default if frontswap is not configured and can only
- * be enabled with the "selfballooning" kernel boot option; similarly
- * selfballooning is enabled by default if frontswap is configured and
- * can be disabled with the "noselfballooning" kernel boot option. Finally,
- * when frontswap is configured, frontswap-selfshrinking can be disabled
- * with the "noselfshrink" kernel boot option.
+ * of the guest memory. Note, that selfballooning should be disabled by default
+ * if frontswap is not configured. Similarly selfballooning should be enabled
+ * by default if frontswap is configured and can be disabled with the
+ * "tmem.selfballooning=0" kernel boot option. Finally, when frontswap is
+ * configured, frontswap-selfshrinking can be disabled with the
+ * "tmem.selfshrink=0" kernel boot option.
*
* Selfballooning is disallowed in domain0 and force-disabled.
*
@@ -120,9 +117,6 @@ static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process);
/* Enable/disable with sysfs. */
static bool frontswap_selfshrinking __read_mostly;
-/* Enable/disable with kernel boot option. */
-static bool use_frontswap_selfshrink = true;
-
/*
* The default values for the following parameters were deemed reasonable
* by experimentation, may be workload-dependent, and can all be
@@ -176,35 +170,6 @@ static void frontswap_selfshrink(void)
frontswap_shrink(tgt_frontswap_pages);
}
-static int __init xen_nofrontswap_selfshrink_setup(char *s)
-{
- use_frontswap_selfshrink = false;
- return 1;
-}
-
-__setup("noselfshrink", xen_nofrontswap_selfshrink_setup);
-
-/* Disable with kernel boot option. */
-static bool use_selfballooning = true;
-
-static int __init xen_noselfballooning_setup(char *s)
-{
- use_selfballooning = false;
- return 1;
-}
-
-__setup("noselfballooning", xen_noselfballooning_setup);
-#else /* !CONFIG_FRONTSWAP */
-/* Enable with kernel boot option. */
-static bool use_selfballooning;
-
-static int __init xen_selfballooning_setup(char *s)
-{
- use_selfballooning = true;
- return 1;
-}
-
-__setup("selfballooning", xen_selfballooning_setup);
#endif /* CONFIG_FRONTSWAP */
#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 61786be..ec097d6 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -534,7 +534,7 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
err = xenbus_map_ring(dev, gnt_ref, &node->handle, addr);
if (err)
- goto out_err;
+ goto out_err_free_ballooned_pages;
spin_lock(&xenbus_valloc_lock);
list_add(&node->next, &xenbus_valloc_pages);
@@ -543,8 +543,9 @@ static int xenbus_map_ring_valloc_hvm(struct xenbus_device *dev,
*vaddr = addr;
return 0;
- out_err:
+ out_err_free_ballooned_pages:
free_xenballooned_pages(1, &node->page);
+ out_err:
kfree(node);
return err;
}
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h
index c8abd3b..e74f9c1 100644
--- a/drivers/xen/xenbus/xenbus_comms.h
+++ b/drivers/xen/xenbus/xenbus_comms.h
@@ -45,6 +45,7 @@ int xb_wait_for_data_to_read(void);
int xs_input_avail(void);
extern struct xenstore_domain_interface *xen_store_interface;
extern int xen_store_evtchn;
+extern enum xenstore_init xen_store_domain_type;
extern const struct file_operations xen_xenbus_fops;
diff --git a/drivers/xen/xenbus/xenbus_dev_backend.c b/drivers/xen/xenbus/xenbus_dev_backend.c
index d730008..a6f42fc0 100644
--- a/drivers/xen/xenbus/xenbus_dev_backend.c
+++ b/drivers/xen/xenbus/xenbus_dev_backend.c
@@ -70,22 +70,21 @@ static long xenbus_alloc(domid_t domid)
return err;
}
-static long xenbus_backend_ioctl(struct file *file, unsigned int cmd, unsigned long data)
+static long xenbus_backend_ioctl(struct file *file, unsigned int cmd,
+ unsigned long data)
{
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
switch (cmd) {
- case IOCTL_XENBUS_BACKEND_EVTCHN:
- if (xen_store_evtchn > 0)
- return xen_store_evtchn;
- return -ENODEV;
-
- case IOCTL_XENBUS_BACKEND_SETUP:
- return xenbus_alloc(data);
-
- default:
- return -ENOTTY;
+ case IOCTL_XENBUS_BACKEND_EVTCHN:
+ if (xen_store_evtchn > 0)
+ return xen_store_evtchn;
+ return -ENODEV;
+ case IOCTL_XENBUS_BACKEND_SETUP:
+ return xenbus_alloc(data);
+ default:
+ return -ENOTTY;
}
}
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 3325884..56cfaaa 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -69,6 +69,9 @@ EXPORT_SYMBOL_GPL(xen_store_evtchn);
struct xenstore_domain_interface *xen_store_interface;
EXPORT_SYMBOL_GPL(xen_store_interface);
+enum xenstore_init xen_store_domain_type;
+EXPORT_SYMBOL_GPL(xen_store_domain_type);
+
static unsigned long xen_store_mfn;
static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
@@ -719,17 +722,11 @@ static int __init xenstored_local_init(void)
return err;
}
-enum xenstore_init {
- UNKNOWN,
- PV,
- HVM,
- LOCAL,
-};
static int __init xenbus_init(void)
{
int err = 0;
- enum xenstore_init usage = UNKNOWN;
uint64_t v = 0;
+ xen_store_domain_type = XS_UNKNOWN;
if (!xen_domain())
return -ENODEV;
@@ -737,29 +734,29 @@ static int __init xenbus_init(void)
xenbus_ring_ops_init();
if (xen_pv_domain())
- usage = PV;
+ xen_store_domain_type = XS_PV;
if (xen_hvm_domain())
- usage = HVM;
+ xen_store_domain_type = XS_HVM;
if (xen_hvm_domain() && xen_initial_domain())
- usage = LOCAL;
+ xen_store_domain_type = XS_LOCAL;
if (xen_pv_domain() && !xen_start_info->store_evtchn)
- usage = LOCAL;
+ xen_store_domain_type = XS_LOCAL;
if (xen_pv_domain() && xen_start_info->store_evtchn)
xenstored_ready = 1;
- switch (usage) {
- case LOCAL:
+ switch (xen_store_domain_type) {
+ case XS_LOCAL:
err = xenstored_local_init();
if (err)
goto out_error;
xen_store_interface = mfn_to_virt(xen_store_mfn);
break;
- case PV:
+ case XS_PV:
xen_store_evtchn = xen_start_info->store_evtchn;
xen_store_mfn = xen_start_info->store_mfn;
xen_store_interface = mfn_to_virt(xen_store_mfn);
break;
- case HVM:
+ case XS_HVM:
err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
if (err)
goto out_error;
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
index bb4f92e..146f857 100644
--- a/drivers/xen/xenbus/xenbus_probe.h
+++ b/drivers/xen/xenbus/xenbus_probe.h
@@ -47,6 +47,13 @@ struct xen_bus_type {
struct bus_type bus;
};
+enum xenstore_init {
+ XS_UNKNOWN,
+ XS_PV,
+ XS_HVM,
+ XS_LOCAL,
+};
+
extern struct device_attribute xenbus_dev_attrs[];
extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index 3159a37..a7e2507 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -29,6 +29,8 @@
#include "xenbus_probe.h"
+static struct workqueue_struct *xenbus_frontend_wq;
+
/* device/<type>/<id> => <type>-<id> */
static int frontend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
{
@@ -89,9 +91,40 @@ static void backend_changed(struct xenbus_watch *watch,
xenbus_otherend_changed(watch, vec, len, 1);
}
+static void xenbus_frontend_delayed_resume(struct work_struct *w)
+{
+ struct xenbus_device *xdev = container_of(w, struct xenbus_device, work);
+
+ xenbus_dev_resume(&xdev->dev);
+}
+
+static int xenbus_frontend_dev_resume(struct device *dev)
+{
+ /*
+ * If xenstored is running in this domain, we cannot access the backend
+ * state at the moment, so we need to defer xenbus_dev_resume
+ */
+ if (xen_store_domain_type == XS_LOCAL) {
+ struct xenbus_device *xdev = to_xenbus_device(dev);
+
+ if (!xenbus_frontend_wq) {
+ pr_err("%s: no workqueue to process delayed resume\n",
+ xdev->nodename);
+ return -EFAULT;
+ }
+
+ INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
+ queue_work(xenbus_frontend_wq, &xdev->work);
+
+ return 0;
+ }
+
+ return xenbus_dev_resume(dev);
+}
+
static const struct dev_pm_ops xenbus_pm_ops = {
.suspend = xenbus_dev_suspend,
- .resume = xenbus_dev_resume,
+ .resume = xenbus_frontend_dev_resume,
.freeze = xenbus_dev_suspend,
.thaw = xenbus_dev_cancel,
.restore = xenbus_dev_resume,
@@ -440,6 +473,8 @@ static int __init xenbus_probe_frontend_init(void)
register_xenstore_notifier(&xenstore_notifier);
+ xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+
return 0;
}
subsys_initcall(xenbus_probe_frontend_init);
OpenPOWER on IntegriCloud