summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/pci_root.c2
-rw-r--r--drivers/atm/solos-pci.c2
-rw-r--r--drivers/block/cciss.c15
-rw-r--r--drivers/block/cciss_cmd.h1
-rw-r--r--drivers/block/floppy.c5
-rw-r--r--drivers/char/Kconfig4
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/bsr.c42
-rw-r--r--drivers/char/tb0219.c4
-rw-r--r--drivers/char/tty_ldisc.c15
-rw-r--r--drivers/char/vr41xx_giu.c680
-rw-r--r--drivers/clocksource/sh_tmu.c2
-rw-r--r--drivers/connector/cn_proc.c3
-rw-r--r--drivers/connector/cn_queue.c7
-rw-r--r--drivers/connector/connector.c6
-rw-r--r--drivers/edac/amd64_edac.c25
-rw-r--r--drivers/edac/amd64_edac.h2
-rw-r--r--drivers/edac/edac_core.h4
-rw-r--r--drivers/edac/edac_mc_sysfs.c4
-rw-r--r--drivers/edac/mpc85xx_edac.c6
-rw-r--r--drivers/edac/mpc85xx_edac.h1
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/pl061.c20
-rw-r--r--drivers/gpio/vr41xx_giu.c586
-rw-r--r--drivers/gpu/drm/Kconfig1
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/drm_edid.c12
-rw-r--r--drivers/gpu/drm/i915/Makefile2
-rw-r--r--drivers/gpu/drm/i915/dvo.h4
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7017.c20
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7xxx.c25
-rw-r--r--drivers/gpu/drm/i915/dvo_ivch.c21
-rw-r--r--drivers/gpu/drm/i915/dvo_sil164.c25
-rw-r--r--drivers/gpu/drm/i915/dvo_tfp410.c25
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c4
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h12
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c19
-rw-r--r--drivers/gpu/drm/i915/i915_gem_debug.c6
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c2
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c12
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h29
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c34
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c12
-rw-r--r--drivers/gpu/drm/i915/intel_display.c199
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c1153
-rw-r--r--drivers/gpu/drm/i915/intel_dp.h144
-rw-r--r--drivers/gpu/drm/i915/intel_dp_i2c.c272
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h17
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c16
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c35
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c16
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c344
-rw-r--r--drivers/gpu/drm/i915/intel_modes.c14
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c72
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c53
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c22
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c33
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c30
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c1
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_vm.c1
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c1
-rw-r--r--drivers/i2c/busses/Kconfig1
-rw-r--r--drivers/ide/cs5520.c1
-rw-r--r--drivers/ide/ide-acpi.c37
-rw-r--r--drivers/ide/ide-cd.c24
-rw-r--r--drivers/ide/ide-devsets.c2
-rw-r--r--drivers/ide/ide-dma.c21
-rw-r--r--drivers/ide/ide-eh.c2
-rw-r--r--drivers/ide/ide-floppy.c2
-rw-r--r--drivers/ide/ide-io.c68
-rw-r--r--drivers/ide/ide-ioctls.c3
-rw-r--r--drivers/ide/ide-iops.c4
-rw-r--r--drivers/ide/ide-pm.c30
-rw-r--r--drivers/ide/ide-probe.c23
-rw-r--r--drivers/ieee802154/fakehard.c132
-rw-r--r--drivers/input/misc/cobalt_btns.c4
-rw-r--r--drivers/isdn/Kconfig6
-rw-r--r--drivers/isdn/act2000/capi.c3
-rw-r--r--drivers/isdn/act2000/module.c31
-rw-r--r--drivers/isdn/hardware/eicon/message.c4
-rw-r--r--drivers/isdn/hardware/eicon/os_4bri.c3
-rw-r--r--drivers/isdn/hardware/mISDN/Kconfig51
-rw-r--r--drivers/isdn/hardware/mISDN/Makefile8
-rw-r--r--drivers/isdn/hardware/mISDN/avmfritz.c1152
-rw-r--r--drivers/isdn/hardware/mISDN/hfcmulti.c23
-rw-r--r--drivers/isdn/hardware/mISDN/hfcpci.c16
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c16
-rw-r--r--drivers/isdn/hardware/mISDN/iohelper.h109
-rw-r--r--drivers/isdn/hardware/mISDN/ipac.h405
-rw-r--r--drivers/isdn/hardware/mISDN/isar.h269
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNinfineon.c1178
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNipac.c1655
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNisar.c1726
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.c1156
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.h58
-rw-r--r--drivers/isdn/hardware/mISDN/speedfax.c526
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.c1440
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.h190
-rw-r--r--drivers/isdn/hisax/Kconfig6
-rw-r--r--drivers/isdn/hisax/Makefile4
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c2
-rw-r--r--drivers/isdn/hisax/callc.c4
-rw-r--r--drivers/isdn/hisax/hfc_pci.c2
-rw-r--r--drivers/isdn/hisax/hfc_sx.c2
-rw-r--r--drivers/isdn/hisax/icc.c2
-rw-r--r--drivers/isdn/hisax/isac.c2
-rw-r--r--drivers/isdn/hisax/isdnhdlc.h70
-rw-r--r--drivers/isdn/hisax/isdnl1.c12
-rw-r--r--drivers/isdn/hisax/isdnl2.c4
-rw-r--r--drivers/isdn/hisax/isdnl3.c4
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c20
-rw-r--r--drivers/isdn/hisax/l3dss1.c26
-rw-r--r--drivers/isdn/hisax/l3ni1.c26
-rw-r--r--drivers/isdn/hisax/q931.c24
-rw-r--r--drivers/isdn/hisax/st5481.h2
-rw-r--r--drivers/isdn/hisax/st5481_b.c5
-rw-r--r--drivers/isdn/hisax/st5481_d.c2
-rw-r--r--drivers/isdn/hisax/st5481_usb.c11
-rw-r--r--drivers/isdn/hisax/tei.c4
-rw-r--r--drivers/isdn/hisax/w6692.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_net.c2
-rw-r--r--drivers/isdn/i4l/Kconfig11
-rw-r--r--drivers/isdn/i4l/Makefile1
-rw-r--r--drivers/isdn/i4l/isdn_net.c16
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c6
-rw-r--r--drivers/isdn/i4l/isdnhdlc.c (renamed from drivers/isdn/hisax/isdnhdlc.c)429
-rw-r--r--drivers/isdn/mISDN/hwchannel.c15
-rw-r--r--drivers/isdn/mISDN/layer2.c2
-rw-r--r--drivers/leds/Kconfig14
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/leds-alix2.c7
-rw-r--r--drivers/leds/leds-bd2802.c96
-rw-r--r--drivers/leds/leds-cobalt-raq.c2
-rw-r--r--drivers/leds/leds-gpio.c22
-rw-r--r--drivers/leds/leds-lp3944.c466
-rw-r--r--drivers/leds/leds-pca9532.c58
-rw-r--r--drivers/lguest/lg.h2
-rw-r--r--drivers/lguest/lguest_user.c4
-rw-r--r--drivers/macintosh/macio_asic.c11
-rw-r--r--drivers/md/dm-exception-store.c9
-rw-r--r--drivers/md/dm-table.c2
-rw-r--r--drivers/md/dm.c4
-rw-r--r--drivers/md/linear.c4
-rw-r--r--drivers/md/md.c56
-rw-r--r--drivers/md/multipath.c7
-rw-r--r--drivers/md/raid0.c9
-rw-r--r--drivers/md/raid1.c9
-rw-r--r--drivers/md/raid10.c19
-rw-r--r--drivers/md/raid5.c28
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c2
-rw-r--r--drivers/message/fusion/mptlan.c2
-rw-r--r--drivers/mfd/ezx-pcap.c4
-rw-r--r--drivers/mfd/sm501.c3
-rw-r--r--drivers/misc/sgi-xp/xpnet.c4
-rw-r--r--drivers/mmc/host/mmc_spi.c6
-rw-r--r--drivers/mtd/cmdlinepart.c2
-rw-r--r--drivers/mtd/devices/m25p80.c2
-rw-r--r--drivers/mtd/inftlcore.c11
-rw-r--r--drivers/mtd/maps/integrator-flash.c22
-rw-r--r--drivers/mtd/nand/atmel_nand.c2
-rw-r--r--drivers/mtd/nand/omap2.c7
-rw-r--r--drivers/mtd/nftlcore.c16
-rw-r--r--drivers/net/3c501.c2
-rw-r--r--drivers/net/3c505.c2
-rw-r--r--drivers/net/3c507.c2
-rw-r--r--drivers/net/3c509.c2
-rw-r--r--drivers/net/3c515.c4
-rw-r--r--drivers/net/3c523.c2
-rw-r--r--drivers/net/3c527.c4
-rw-r--r--drivers/net/3c59x.c4
-rw-r--r--drivers/net/7990.c2
-rw-r--r--drivers/net/8139cp.c2
-rw-r--r--drivers/net/8139too.c4
-rw-r--r--drivers/net/82596.c4
-rw-r--r--drivers/net/a2065.c4
-rw-r--r--drivers/net/amd8111e.c2
-rw-r--r--drivers/net/appletalk/cops.c2
-rw-r--r--drivers/net/appletalk/ipddp.c4
-rw-r--r--drivers/net/appletalk/ltpc.c2
-rw-r--r--drivers/net/ariadne.c4
-rw-r--r--drivers/net/arm/am79c961a.c2
-rw-r--r--drivers/net/arm/at91_ether.c2
-rw-r--r--drivers/net/arm/ether1.c2
-rw-r--r--drivers/net/arm/ether3.c4
-rw-r--r--drivers/net/at1700.c2
-rw-r--r--drivers/net/atarilance.c4
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/au1000_eth.c2
-rw-r--r--drivers/net/b44.c8
-rw-r--r--drivers/net/benet/Kconfig1
-rw-r--r--drivers/net/benet/be.h11
-rw-r--r--drivers/net/benet/be_ethtool.c9
-rw-r--r--drivers/net/benet/be_main.c104
-rw-r--r--drivers/net/bfin_mac.c2
-rw-r--r--drivers/net/bmac.c2
-rw-r--r--drivers/net/bnx2.c19
-rw-r--r--drivers/net/bnx2x.h3
-rw-r--r--drivers/net/bnx2x_hsi.h40
-rw-r--r--drivers/net/bnx2x_link.c1100
-rw-r--r--drivers/net/bnx2x_link.h14
-rw-r--r--drivers/net/bnx2x_main.c265
-rw-r--r--drivers/net/bnx2x_reg.h33
-rw-r--r--drivers/net/bonding/bond_3ad.c5
-rw-r--r--drivers/net/bonding/bond_alb.c2
-rw-r--r--drivers/net/bonding/bond_main.c8
-rw-r--r--drivers/net/can/Kconfig7
-rw-r--r--drivers/net/can/sja1000/ems_pci.c152
-rw-r--r--drivers/net/can/sja1000/sja1000.c2
-rw-r--r--drivers/net/cassini.c4
-rw-r--r--drivers/net/cris/eth_v10.c2
-rw-r--r--drivers/net/cs89x0.c4
-rw-r--r--drivers/net/cxgb3/adapter.h10
-rw-r--r--drivers/net/cxgb3/ael1002.c1193
-rw-r--r--drivers/net/cxgb3/aq100x.c7
-rw-r--r--drivers/net/cxgb3/common.h10
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c99
-rw-r--r--drivers/net/cxgb3/t3_hw.c2
-rw-r--r--drivers/net/cxgb3/xgmac.c11
-rw-r--r--drivers/net/de600.c2
-rw-r--r--drivers/net/de620.c2
-rw-r--r--drivers/net/declance.c4
-rw-r--r--drivers/net/defxx.c6
-rw-r--r--drivers/net/depca.c2
-rw-r--r--drivers/net/dm9000.c127
-rw-r--r--drivers/net/dm9000.h18
-rw-r--r--drivers/net/dnet.c2
-rw-r--r--drivers/net/dummy.c2
-rw-r--r--drivers/net/e100.c2
-rw-r--r--drivers/net/e1000/e1000.h7
-rw-r--r--drivers/net/e1000/e1000_ethtool.c51
-rw-r--r--drivers/net/e1000/e1000_hw.c2
-rw-r--r--drivers/net/e1000/e1000_hw.h3
-rw-r--r--drivers/net/e1000/e1000_main.c483
-rw-r--r--drivers/net/eepro.c4
-rw-r--r--drivers/net/eexpress.c4
-rw-r--r--drivers/net/enc28j60.c2
-rw-r--r--drivers/net/epic100.c4
-rw-r--r--drivers/net/eql.c2
-rw-r--r--drivers/net/eth16i.c4
-rw-r--r--drivers/net/ethoc.c2
-rw-r--r--drivers/net/ewrk3.c2
-rw-r--r--drivers/net/fealnx.c2
-rw-r--r--drivers/net/fec.c2
-rw-r--r--drivers/net/fs_enet/mii-fec.c37
-rw-r--r--drivers/net/gianfar.c1
-rw-r--r--drivers/net/hamachi.c2
-rw-r--r--drivers/net/hamradio/6pack.c2
-rw-r--r--drivers/net/hamradio/baycom_epp.c6
-rw-r--r--drivers/net/hamradio/bpqether.c2
-rw-r--r--drivers/net/hamradio/dmascc.c2
-rw-r--r--drivers/net/hamradio/hdlcdrv.c4
-rw-r--r--drivers/net/hamradio/mkiss.c2
-rw-r--r--drivers/net/hamradio/scc.c6
-rw-r--r--drivers/net/hamradio/yam.c2
-rw-r--r--drivers/net/hp100.c6
-rw-r--r--drivers/net/ibm_newemac/core.c2
-rw-r--r--drivers/net/ibmveth.c2
-rw-r--r--drivers/net/ifb.c2
-rw-r--r--drivers/net/igb/e1000_82575.c193
-rw-r--r--drivers/net/igb/e1000_82575.h6
-rw-r--r--drivers/net/igb/e1000_defines.h8
-rw-r--r--drivers/net/igb/e1000_hw.h18
-rw-r--r--drivers/net/igb/e1000_mac.c175
-rw-r--r--drivers/net/igb/e1000_mac.h3
-rw-r--r--drivers/net/igb/e1000_phy.c4
-rw-r--r--drivers/net/igb/e1000_regs.h1
-rw-r--r--drivers/net/igb/igb_ethtool.c65
-rw-r--r--drivers/net/igb/igb_main.c121
-rw-r--r--drivers/net/igbvf/netdev.c5
-rw-r--r--drivers/net/ioc3-eth.c2
-rw-r--r--drivers/net/irda/ali-ircc.c12
-rw-r--r--drivers/net/irda/au1k_ir.c4
-rw-r--r--drivers/net/irda/donauboe.c8
-rw-r--r--drivers/net/irda/irda-usb.c2
-rw-r--r--drivers/net/irda/nsc-ircc.c10
-rw-r--r--drivers/net/irda/pxaficp_ir.c4
-rw-r--r--drivers/net/irda/sa1100_ir.c4
-rw-r--r--drivers/net/irda/sir_dev.c6
-rw-r--r--drivers/net/irda/smsc-ircc2.c16
-rw-r--r--drivers/net/irda/stir4200.c2
-rw-r--r--drivers/net/irda/via-ircc.c12
-rw-r--r--drivers/net/irda/vlsi_ir.c6
-rw-r--r--drivers/net/irda/w83977af_ir.c4
-rw-r--r--drivers/net/isa-skeleton.c2
-rw-r--r--drivers/net/iseries_veth.c4
-rw-r--r--drivers/net/ixgb/ixgb_main.c2
-rw-r--r--drivers/net/ixgbe/ixgbe.h4
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c1
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c33
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c12
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h32
-rw-r--r--drivers/net/ixp2000/ixpdev.c4
-rw-r--r--drivers/net/jazzsonic.c4
-rw-r--r--drivers/net/jme.c189
-rw-r--r--drivers/net/jme.h21
-rw-r--r--drivers/net/lance.c2
-rw-r--r--drivers/net/lib82596.c4
-rw-r--r--drivers/net/lib8390.c2
-rw-r--r--drivers/net/ll_temac_main.c2
-rw-r--r--drivers/net/loopback.c2
-rw-r--r--drivers/net/lp486e.c4
-rw-r--r--drivers/net/mac89x0.c2
-rw-r--r--drivers/net/macb.c2
-rw-r--r--drivers/net/mace.c2
-rw-r--r--drivers/net/meth.c4
-rw-r--r--drivers/net/mipsnet.c2
-rw-r--r--drivers/net/mlx4/en_tx.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c10
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/natsemi.c2
-rw-r--r--drivers/net/netx-eth.c2
-rw-r--r--drivers/net/netxen/netxen_nic.h177
-rw-r--r--drivers/net/netxen/netxen_nic_ctx.c6
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c81
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h2
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c28
-rw-r--r--drivers/net/netxen/netxen_nic_init.c130
-rw-r--r--drivers/net/netxen/netxen_nic_main.c588
-rw-r--r--drivers/net/ni5010.c2
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni65.c2
-rw-r--r--drivers/net/pci-skeleton.c2
-rw-r--r--drivers/net/pcmcia/3c574_cs.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c2
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c4
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c2
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c6
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c4
-rw-r--r--drivers/net/pcnet32.c2
-rw-r--r--drivers/net/phy/Kconfig6
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/bcm63xx.c132
-rw-r--r--drivers/net/plip.c2
-rw-r--r--drivers/net/ppp_generic.c4
-rw-r--r--drivers/net/r6040.c4
-rw-r--r--drivers/net/rionet.c7
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/s2io.c10
-rw-r--r--drivers/net/sb1000.c2
-rw-r--r--drivers/net/sb1250-mac.c4
-rw-r--r--drivers/net/seeq8005.c4
-rw-r--r--drivers/net/sgiseeq.c6
-rw-r--r--drivers/net/sh_eth.c2
-rw-r--r--drivers/net/sis900.c2
-rw-r--r--drivers/net/skfp/skfddi.c4
-rw-r--r--drivers/net/sky2.c2
-rw-r--r--drivers/net/slip.c6
-rw-r--r--drivers/net/smc911x.c6
-rw-r--r--drivers/net/smc9194.c8
-rw-r--r--drivers/net/smc91x.c4
-rw-r--r--drivers/net/sonic.c4
-rw-r--r--drivers/net/starfire.c2
-rw-r--r--drivers/net/sun3_82586.c4
-rw-r--r--drivers/net/sun3lance.c4
-rw-r--r--drivers/net/sunbmac.c2
-rw-r--r--drivers/net/sundance.c2
-rw-r--r--drivers/net/sunhme.c2
-rw-r--r--drivers/net/sunlance.c2
-rw-r--r--drivers/net/sunqe.c2
-rw-r--r--drivers/net/tc35815.c2
-rw-r--r--drivers/net/tlan.c6
-rw-r--r--drivers/net/tokenring/3c359.c2
-rw-r--r--drivers/net/tokenring/ibmtr.c2
-rw-r--r--drivers/net/tokenring/lanstreamer.c2
-rw-r--r--drivers/net/tokenring/olympic.c2
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tokenring/tms380tr.c2
-rw-r--r--drivers/net/tulip/de2104x.c2
-rw-r--r--drivers/net/tulip/dmfe.c4
-rw-r--r--drivers/net/tulip/tulip_core.c2
-rw-r--r--drivers/net/tulip/uli526x.c4
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/tulip/xircom_cb.c2
-rw-r--r--drivers/net/tun.c18
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/ucc_geth.c42
-rw-r--r--drivers/net/ucc_geth.h2
-rw-r--r--drivers/net/usb/catc.c2
-rw-r--r--drivers/net/usb/hso.c2
-rw-r--r--drivers/net/usb/kaweth.c4
-rw-r--r--drivers/net/usb/pegasus.c2
-rw-r--r--drivers/net/usb/rtl8150.c2
-rw-r--r--drivers/net/usb/usbnet.c14
-rw-r--r--drivers/net/veth.c7
-rw-r--r--drivers/net/via-rhine.c6
-rw-r--r--drivers/net/via-velocity.c3431
-rw-r--r--drivers/net/via-velocity.h6
-rw-r--r--drivers/net/virtio_net.c3
-rw-r--r--drivers/net/vxge/vxge-config.c10
-rw-r--r--drivers/net/vxge/vxge-config.h10
-rw-r--r--drivers/net/vxge/vxge-main.c100
-rw-r--r--drivers/net/vxge/vxge-main.h4
-rw-r--r--drivers/net/vxge/vxge-reg.h9
-rw-r--r--drivers/net/vxge/vxge-traffic.h2
-rw-r--r--drivers/net/vxge/vxge-version.h2
-rw-r--r--drivers/net/wan/cycx_x25.c2
-rw-r--r--drivers/net/wan/dlci.c4
-rw-r--r--drivers/net/wan/dscc4.c2
-rw-r--r--drivers/net/wan/farsync.c27
-rw-r--r--drivers/net/wan/hdlc_fr.c6
-rw-r--r--drivers/net/wan/lmc/lmc_main.c2
-rw-r--r--drivers/net/wan/sbni.c4
-rw-r--r--drivers/net/wan/wanxl.c2
-rw-r--r--drivers/net/wan/x25_asy.c10
-rw-r--r--drivers/net/wimax/i2400m/sdio.c12
-rw-r--r--drivers/net/wireless/Kconfig6
-rw-r--r--drivers/net/wireless/adm8211.c20
-rw-r--r--drivers/net/wireless/airo.c14
-rw-r--r--drivers/net/wireless/arlan-main.c4
-rw-r--r--drivers/net/wireless/at76c50x-usb.c3
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h52
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c615
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h21
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c130
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h10
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c8
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/reg.h12
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h50
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c22
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c72
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h18
-rw-r--r--drivers/net/wireless/ath/ath9k/initvals.h47
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c30
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c97
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c609
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h29
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c92
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h93
-rw-r--r--drivers/net/wireless/ath/ath9k/virtual.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c107
-rw-r--r--drivers/net/wireless/ath/regd.c2
-rw-r--r--drivers/net/wireless/atmel.c6
-rw-r--r--drivers/net/wireless/b43/main.c4
-rw-r--r--drivers/net/wireless/b43/xmit.c3
-rw-r--r--drivers/net/wireless/b43legacy/xmit.c3
-rw-r--r--drivers/net/wireless/hostap/hostap_80211_tx.c42
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c3
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c13
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_tx.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-rs.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c58
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c69
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c89
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c16
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c239
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c487
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c78
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h36
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c31
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c22
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c177
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c373
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c148
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c21
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c16
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h37
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c45
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c27
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c132
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.h3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/wext.c618
-rw-r--r--drivers/net/wireless/libertas/assoc.c16
-rw-r--r--drivers/net/wireless/libertas/dev.h1
-rw-r--r--drivers/net/wireless/libertas/if_cs.c3
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c5
-rw-r--r--drivers/net/wireless/libertas/if_spi.c8
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/wext.c2
-rw-r--r--drivers/net/wireless/libertas_tf/main.c3
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c91
-rw-r--r--drivers/net/wireless/mwl8k.c9
-rw-r--r--drivers/net/wireless/netwave_cs.c2
-rw-r--r--drivers/net/wireless/orinoco/Kconfig1
-rw-r--r--drivers/net/wireless/orinoco/Makefile2
-rw-r--r--drivers/net/wireless/orinoco/airport.c98
-rw-r--r--drivers/net/wireless/orinoco/cfg.c162
-rw-r--r--drivers/net/wireless/orinoco/cfg.h15
-rw-r--r--drivers/net/wireless/orinoco/fw.c41
-rw-r--r--drivers/net/wireless/orinoco/hermes.c2
-rw-r--r--drivers/net/wireless/orinoco/hermes.h2
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c50
-rw-r--r--drivers/net/wireless/orinoco/hw.c668
-rw-r--r--drivers/net/wireless/orinoco/hw.h11
-rw-r--r--drivers/net/wireless/orinoco/main.c1132
-rw-r--r--drivers/net/wireless/orinoco/main.h3
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h49
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c96
-rw-r--r--drivers/net/wireless/orinoco/orinoco_nortel.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.h57
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c38
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c38
-rw-r--r--drivers/net/wireless/orinoco/scan.c291
-rw-r--r--drivers/net/wireless/orinoco/scan.h21
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c96
-rw-r--r--drivers/net/wireless/orinoco/wext.c878
-rw-r--r--drivers/net/wireless/p54/Makefile3
-rw-r--r--drivers/net/wireless/p54/eeprom.c753
-rw-r--r--drivers/net/wireless/p54/eeprom.h226
-rw-r--r--drivers/net/wireless/p54/fwio.c715
-rw-r--r--drivers/net/wireless/p54/led.c163
-rw-r--r--drivers/net/wireless/p54/lmac.h558
-rw-r--r--drivers/net/wireless/p54/main.c637
-rw-r--r--drivers/net/wireless/p54/p54.h151
-rw-r--r--drivers/net/wireless/p54/p54common.c2688
-rw-r--r--drivers/net/wireless/p54/p54common.h644
-rw-r--r--drivers/net/wireless/p54/p54pci.c9
-rw-r--r--drivers/net/wireless/p54/p54spi.c50
-rw-r--r--drivers/net/wireless/p54/p54usb.c42
-rw-r--r--drivers/net/wireless/p54/txrx.c860
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c4
-rw-r--r--drivers/net/wireless/ray_cs.c6
-rw-r--r--drivers/net/wireless/rndis_wlan.c298
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig8
-rw-r--r--drivers/net/wireless/rt2x00/Makefile1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c16
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h20
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h21
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c26
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h10
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00reg.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00rfkill.c127
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c10
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h2
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c8
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180_dev.c5
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_dev.c3
-rw-r--r--drivers/net/wireless/strip.c2
-rw-r--r--drivers/net/wireless/wavelan.c2
-rw-r--r--drivers/net/wireless/wavelan_cs.c4
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig17
-rw-r--r--drivers/net/wireless/wl12xx/Makefile9
-rw-r--r--drivers/net/wireless/wl12xx/acx.c689
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c353
-rw-r--r--drivers/net/wireless/wl12xx/reg.h1
-rw-r--r--drivers/net/wireless/wl12xx/wl1251.h479
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.c840
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h (renamed from drivers/net/wireless/wl12xx/acx.h)199
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.c (renamed from drivers/net/wireless/wl12xx/boot.c)114
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_boot.h (renamed from drivers/net/wireless/wl12xx/boot.h)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.c428
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h (renamed from drivers/net/wireless/wl12xx/cmd.h)194
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.c (renamed from drivers/net/wireless/wl12xx/debugfs.c)60
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_debugfs.h (renamed from drivers/net/wireless/wl12xx/debugfs.h)16
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.c (renamed from drivers/net/wireless/wl12xx/event.c)54
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.h (renamed from drivers/net/wireless/wl12xx/event.h)12
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.c (renamed from drivers/net/wireless/wl12xx/init.c)78
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_init.h (renamed from drivers/net/wireless/wl12xx/init.h)27
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c (renamed from drivers/net/wireless/wl12xx/main.c)659
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_netlink.h30
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ops.c (renamed from drivers/net/wireless/wl12xx/wl1251.c)299
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ops.h165
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.c (renamed from drivers/net/wireless/wl12xx/ps.c)64
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_ps.h (renamed from drivers/net/wireless/wl12xx/ps.h)18
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.c (renamed from drivers/net/wireless/wl12xx/rx.c)90
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.h (renamed from drivers/net/wireless/wl12xx/rx.h)24
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.c (renamed from drivers/net/wireless/wl12xx/spi.c)179
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_spi.h (renamed from drivers/net/wireless/wl12xx/spi.h)62
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.c (renamed from drivers/net/wireless/wl12xx/tx.c)124
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.h (renamed from drivers/net/wireless/wl12xx/tx.h)21
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h409
-rw-r--r--drivers/net/wireless/wl3501_cs.c3
-rw-r--r--drivers/net/wireless/zd1201.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c74
-rw-r--r--drivers/net/xen-netfront.c4
-rw-r--r--drivers/net/xtsonic.c2
-rw-r--r--drivers/net/yellowfin.c4
-rw-r--r--drivers/net/znet.c4
-rw-r--r--drivers/parisc/ccio-dma.c7
-rw-r--r--drivers/parisc/dino.c12
-rw-r--r--drivers/parisc/eisa.c2
-rw-r--r--drivers/parisc/gsc.c4
-rw-r--r--drivers/parisc/gsc.h2
-rw-r--r--drivers/parisc/iosapic.c2
-rw-r--r--drivers/parisc/lba_pci.c41
-rw-r--r--drivers/parisc/sba_iommu.c2
-rw-r--r--drivers/parisc/superio.c6
-rw-r--r--drivers/parport/parport_pc.c5
-rw-r--r--drivers/pci/intel-iommu.c704
-rw-r--r--drivers/pci/iova.c26
-rw-r--r--drivers/pcmcia/vrc4171_card.c4
-rw-r--r--drivers/pcmcia/vrc4173_cardu.c4
-rw-r--r--drivers/pcmcia/vrc4173_cardu.h2
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/eeepc-laptop.c346
-rw-r--r--drivers/rtc/rtc-bfin.c30
-rw-r--r--drivers/rtc/rtc-vr41xx.c4
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/ctcm_main.c10
-rw-r--r--drivers/s390/net/lcs.c8
-rw-r--r--drivers/s390/net/netiucv.c6
-rw-r--r--drivers/s390/net/qeth_l2_main.c1
-rw-r--r--drivers/s390/net/qeth_l3_main.c1
-rw-r--r--drivers/scsi/cxgb3i/Kbuild2
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_iscsi.c4
-rw-r--r--drivers/scsi/fnic/fnic_main.c8
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c7
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c7
-rw-r--r--drivers/scsi/scsi_transport_fc.c5
-rw-r--r--drivers/scsi/sg.c4
-rw-r--r--drivers/scsi/zalon.c2
-rw-r--r--drivers/serial/8250_pci.c6
-rw-r--r--drivers/serial/vr41xx_siu.c2
-rw-r--r--drivers/spi/omap_uwire.c2
-rw-r--r--drivers/spi/spi_bitbang.c24
-rw-r--r--drivers/spi/spidev.c17
-rw-r--r--drivers/ssb/driver_mipscore.c85
-rw-r--r--drivers/staging/agnx/xmit.c3
-rw-r--r--drivers/staging/at76_usb/at76_usb.c8
-rw-r--r--drivers/staging/dst/dcore.c3
-rw-r--r--drivers/staging/epl/VirtualEthernetLinux.c2
-rw-r--r--drivers/staging/otus/usbdrv.c8
-rw-r--r--drivers/staging/otus/wrap_pkt.c3
-rw-r--r--drivers/staging/rt2860/rt_main_dev.c6
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c4
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c4
-rw-r--r--drivers/staging/slicoss/slicoss.c2
-rw-r--r--drivers/staging/stlc45xx/stlc45xx.c3
-rw-r--r--drivers/staging/winbond/wb35rx.c3
-rw-r--r--drivers/staging/wlan-ng/p80211netdev.c2
-rw-r--r--drivers/usb/class/cdc-acm.c4
-rw-r--r--drivers/usb/gadget/f_phonet.c2
-rw-r--r--drivers/usb/gadget/u_ether.c6
-rw-r--r--drivers/usb/serial/usb-serial.c3
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/atafb.c7
-rw-r--r--drivers/video/atmel_lcdfb.c2
-rw-r--r--drivers/video/aty/atyfb.h3
-rw-r--r--drivers/video/aty/atyfb_base.c141
-rw-r--r--drivers/video/aty/mach64_accel.c7
-rw-r--r--drivers/video/backlight/tdo24m.c2
-rw-r--r--drivers/video/cobalt_lcdfb.c2
-rw-r--r--drivers/video/fbmem.c13
-rw-r--r--drivers/video/fsl-diu-fb.c14
-rw-r--r--drivers/video/i810/i810_main.c2
-rw-r--r--drivers/video/matrox/matroxfb_base.c3
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c5
-rw-r--r--drivers/video/mx3fb.c17
-rw-r--r--drivers/video/omap/omapfb_main.c4
-rw-r--r--drivers/video/platinumfb.c2
-rw-r--r--drivers/video/pxafb.c2
-rw-r--r--drivers/video/sh7760fb.c19
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c53
-rw-r--r--drivers/video/sis/sis_main.c2
-rw-r--r--drivers/video/sm501fb.c23
-rw-r--r--drivers/video/uvesafb.c3
-rw-r--r--drivers/video/w100fb.c2
-rw-r--r--drivers/w1/w1_netlink.c3
-rw-r--r--drivers/watchdog/wdrtas.c8
694 files changed, 33158 insertions, 18132 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 8a5bf3b356f..55b5b90c2a4 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -395,7 +395,7 @@ struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
fn = adr & 0xffff;
pdev = pci_get_slot(pbus, PCI_DEVFN(dev, fn));
- if (hnd == handle)
+ if (!pdev || hnd == handle)
break;
pbus = pdev->subordinate;
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 9359613addc..307321b32cb 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -372,7 +372,7 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb
}
snr = next_string(skb);
- if (!str)
+ if (!snr)
return -EIO;
attn = next_string(skb);
if (!attn)
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index c7a527c08a0..65a0655e7fc 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -226,8 +226,18 @@ static inline void addQ(struct hlist_head *list, CommandList_struct *c)
static inline void removeQ(CommandList_struct *c)
{
- if (WARN_ON(hlist_unhashed(&c->list)))
+ /*
+ * After kexec/dump some commands might still
+ * be in flight, which the firmware will try
+ * to complete. Resetting the firmware doesn't work
+ * with old fw revisions, so we have to mark
+ * them off as 'stale' to prevent the driver from
+ * falling over.
+ */
+ if (WARN_ON(hlist_unhashed(&c->list))) {
+ c->cmd_type = CMD_MSG_STALE;
return;
+ }
hlist_del_init(&c->list);
}
@@ -4246,7 +4256,8 @@ static void fail_all_cmds(unsigned long ctlr)
while (!hlist_empty(&h->cmpQ)) {
c = hlist_entry(h->cmpQ.first, CommandList_struct, list);
removeQ(c);
- c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+ if (c->cmd_type != CMD_MSG_STALE)
+ c->err_info->CommandStatus = CMD_HARDWARE_ERR;
if (c->cmd_type == CMD_RWREQ) {
complete_command(h, c, 0);
} else if (c->cmd_type == CMD_IOCTL_PEND)
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index cd665b00c7c..dbaed1ea0da 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -274,6 +274,7 @@ typedef struct _ErrorInfo_struct {
#define CMD_SCSI 0x03
#define CMD_MSG_DONE 0x04
#define CMD_MSG_TIMEOUT 0x05
+#define CMD_MSG_STALE 0xff
/* This structure needs to be divisible by 8 for new
* indexing method.
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 862b40c9018..91b75301378 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3327,7 +3327,10 @@ static inline int set_geometry(unsigned int cmd, struct floppy_struct *g,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
mutex_lock(&open_lock);
- LOCK_FDC(drive, 1);
+ if (lock_fdc(drive, 1)) {
+ mutex_unlock(&open_lock);
+ return -EINTR;
+ }
floppy_type[type] = *g;
floppy_type[type].name = "user format";
for (cnt = type << 2; cnt < (type << 2) + 4; cnt++)
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 0bd01f49cfd..6a06913b01d 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -1029,10 +1029,6 @@ config CS5535_GPIO
If compiled as a module, it will be called cs5535_gpio.
-config GPIO_VR41XX
- tristate "NEC VR4100 series General-purpose I/O Unit support"
- depends on CPU_VR41XX
-
config RAW_DRIVER
tristate "RAW driver (/dev/raw/rawN)"
depends on BLOCK
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 189efcff08c..66f779ad4f4 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -95,7 +95,6 @@ obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
-obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 140ea10ecb8..c02db01f736 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -27,6 +27,7 @@
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/mm.h>
+#include <asm/pgtable.h>
#include <asm/io.h>
/*
@@ -75,12 +76,13 @@ static struct class *bsr_class;
static int bsr_major;
enum {
- BSR_8 = 0,
- BSR_16 = 1,
- BSR_64 = 2,
- BSR_128 = 3,
- BSR_UNKNOWN = 4,
- BSR_MAX = 5,
+ BSR_8 = 0,
+ BSR_16 = 1,
+ BSR_64 = 2,
+ BSR_128 = 3,
+ BSR_4096 = 4,
+ BSR_UNKNOWN = 5,
+ BSR_MAX = 6,
};
static unsigned bsr_types[BSR_MAX];
@@ -117,15 +119,22 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long size = vma->vm_end - vma->vm_start;
struct bsr_dev *dev = filp->private_data;
+ int ret;
- if (size > dev->bsr_len || (size & (PAGE_SIZE-1)))
- return -EINVAL;
-
- vma->vm_flags |= (VM_IO | VM_DONTEXPAND);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT,
- size, vma->vm_page_prot))
+ /* check for the case of a small BSR device and map one 4k page for it*/
+ if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE)
+ ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
+ vma->vm_page_prot);
+ else if (size <= dev->bsr_len)
+ ret = io_remap_pfn_range(vma, vma->vm_start,
+ dev->bsr_addr >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+ else
+ return -EINVAL;
+
+ if (ret)
return -EAGAIN;
return 0;
@@ -205,6 +214,11 @@ static int bsr_add_node(struct device_node *bn)
cur->bsr_stride = bsr_stride[i];
cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs);
+ /* if we have a bsr_len of > 4k and less then PAGE_SIZE (64k pages) */
+ /* we can only map 4k of it, so only advertise the 4k in sysfs */
+ if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE)
+ cur->bsr_len = 4096;
+
switch(cur->bsr_bytes) {
case 8:
cur->bsr_type = BSR_8;
@@ -218,9 +232,11 @@ static int bsr_add_node(struct device_node *bn)
case 128:
cur->bsr_type = BSR_128;
break;
+ case 4096:
+ cur->bsr_type = BSR_4096;
+ break;
default:
cur->bsr_type = BSR_UNKNOWN;
- printk(KERN_INFO "unknown BSR size %d\n",cur->bsr_bytes);
}
cur->bsr_num = bsr_types[cur->bsr_type];
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
index 6062b62800f..b3ec9b10e29 100644
--- a/drivers/char/tb0219.c
+++ b/drivers/char/tb0219.c
@@ -1,7 +1,7 @@
/*
* Driver for TANBAC TB0219 base board.
*
- * Copyright (C) 2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2005 Yoichi Yuasa <yuasa@linux-mips.org>
*
* 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
@@ -28,7 +28,7 @@
#include <asm/vr41xx/giu.h>
#include <asm/vr41xx/tb0219.h>
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index a19e935847b..913aa8d3f1c 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -867,15 +867,22 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_wait_idle(tty);
/*
- * Shutdown the current line discipline, and reset it to N_TTY.
- *
- * FIXME: this MUST get fixed for the new reflocking
+ * Now kill off the ldisc
*/
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ /* Force an oops if we mess this up */
+ tty->ldisc = NULL;
+
+ /* Ensure the next open requests the N_TTY ldisc */
+ tty_set_termios_ldisc(tty, N_TTY);
- tty_ldisc_reinit(tty);
/* This will need doing differently if we need to lock */
if (o_tty)
tty_ldisc_release(o_tty, NULL);
+
+ /* And the memory resources remaining (buffers, termios) will be
+ disposed of when the kref hits zero */
}
/**
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index 54c837288d1..e69de29bb2d 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -1,680 +0,0 @@
-/*
- * Driver for NEC VR4100 series General-purpose I/O Unit.
- *
- * Copyright (C) 2002 MontaVista Software Inc.
- * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- * Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-#include <asm/vr41xx/giu.h>
-#include <asm/vr41xx/irq.h>
-#include <asm/vr41xx/vr41xx.h>
-
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
-MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
-MODULE_LICENSE("GPL");
-
-static int major; /* default is dynamic major device number */
-module_param(major, int, 0);
-MODULE_PARM_DESC(major, "Major device number");
-
-#define GIUIOSELL 0x00
-#define GIUIOSELH 0x02
-#define GIUPIODL 0x04
-#define GIUPIODH 0x06
-#define GIUINTSTATL 0x08
-#define GIUINTSTATH 0x0a
-#define GIUINTENL 0x0c
-#define GIUINTENH 0x0e
-#define GIUINTTYPL 0x10
-#define GIUINTTYPH 0x12
-#define GIUINTALSELL 0x14
-#define GIUINTALSELH 0x16
-#define GIUINTHTSELL 0x18
-#define GIUINTHTSELH 0x1a
-#define GIUPODATL 0x1c
-#define GIUPODATEN 0x1c
-#define GIUPODATH 0x1e
- #define PIOEN0 0x0100
- #define PIOEN1 0x0200
-#define GIUPODAT 0x1e
-#define GIUFEDGEINHL 0x20
-#define GIUFEDGEINHH 0x22
-#define GIUREDGEINHL 0x24
-#define GIUREDGEINHH 0x26
-
-#define GIUUSEUPDN 0x1e0
-#define GIUTERMUPDN 0x1e2
-
-#define GPIO_HAS_PULLUPDOWN_IO 0x0001
-#define GPIO_HAS_OUTPUT_ENABLE 0x0002
-#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
-
-static spinlock_t giu_lock;
-static unsigned long giu_flags;
-static unsigned int giu_nr_pins;
-
-static void __iomem *giu_base;
-
-#define giu_read(offset) readw(giu_base + (offset))
-#define giu_write(offset, value) writew((value), giu_base + (offset))
-
-#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE)
-#define GIUINT_HIGH_OFFSET 16
-#define GIUINT_HIGH_MAX 32
-
-static inline uint16_t giu_set(uint16_t offset, uint16_t set)
-{
- uint16_t data;
-
- data = giu_read(offset);
- data |= set;
- giu_write(offset, data);
-
- return data;
-}
-
-static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
-{
- uint16_t data;
-
- data = giu_read(offset);
- data &= ~clear;
- giu_write(offset, data);
-
- return data;
-}
-
-static void ack_giuint_low(unsigned int irq)
-{
- giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static void mask_giuint_low(unsigned int irq)
-{
- giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static void mask_ack_giuint_low(unsigned int irq)
-{
- unsigned int pin;
-
- pin = GPIO_PIN_OF_IRQ(irq);
- giu_clear(GIUINTENL, 1 << pin);
- giu_write(GIUINTSTATL, 1 << pin);
-}
-
-static void unmask_giuint_low(unsigned int irq)
-{
- giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static struct irq_chip giuint_low_irq_chip = {
- .name = "GIUINTL",
- .ack = ack_giuint_low,
- .mask = mask_giuint_low,
- .mask_ack = mask_ack_giuint_low,
- .unmask = unmask_giuint_low,
-};
-
-static void ack_giuint_high(unsigned int irq)
-{
- giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_giuint_high(unsigned int irq)
-{
- giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_ack_giuint_high(unsigned int irq)
-{
- unsigned int pin;
-
- pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
- giu_clear(GIUINTENH, 1 << pin);
- giu_write(GIUINTSTATH, 1 << pin);
-}
-
-static void unmask_giuint_high(unsigned int irq)
-{
- giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static struct irq_chip giuint_high_irq_chip = {
- .name = "GIUINTH",
- .ack = ack_giuint_high,
- .mask = mask_giuint_high,
- .mask_ack = mask_ack_giuint_high,
- .unmask = unmask_giuint_high,
-};
-
-static int giu_get_irq(unsigned int irq)
-{
- uint16_t pendl, pendh, maskl, maskh;
- int i;
-
- pendl = giu_read(GIUINTSTATL);
- pendh = giu_read(GIUINTSTATH);
- maskl = giu_read(GIUINTENL);
- maskh = giu_read(GIUINTENH);
-
- maskl &= pendl;
- maskh &= pendh;
-
- if (maskl) {
- for (i = 0; i < 16; i++) {
- if (maskl & (1 << i))
- return GIU_IRQ(i);
- }
- } else if (maskh) {
- for (i = 0; i < 16; i++) {
- if (maskh & (1 << i))
- return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
- }
- }
-
- printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
- maskl, pendl, maskh, pendh);
-
- atomic_inc(&irq_err_count);
-
- return -EINVAL;
-}
-
-void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal)
-{
- uint16_t mask;
-
- if (pin < GIUINT_HIGH_OFFSET) {
- mask = 1 << pin;
- if (trigger != IRQ_TRIGGER_LEVEL) {
- giu_set(GIUINTTYPL, mask);
- if (signal == IRQ_SIGNAL_HOLD)
- giu_set(GIUINTHTSELL, mask);
- else
- giu_clear(GIUINTHTSELL, mask);
- if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
- switch (trigger) {
- case IRQ_TRIGGER_EDGE_FALLING:
- giu_set(GIUFEDGEINHL, mask);
- giu_clear(GIUREDGEINHL, mask);
- break;
- case IRQ_TRIGGER_EDGE_RISING:
- giu_clear(GIUFEDGEINHL, mask);
- giu_set(GIUREDGEINHL, mask);
- break;
- default:
- giu_set(GIUFEDGEINHL, mask);
- giu_set(GIUREDGEINHL, mask);
- break;
- }
- }
- set_irq_chip_and_handler(GIU_IRQ(pin),
- &giuint_low_irq_chip,
- handle_edge_irq);
- } else {
- giu_clear(GIUINTTYPL, mask);
- giu_clear(GIUINTHTSELL, mask);
- set_irq_chip_and_handler(GIU_IRQ(pin),
- &giuint_low_irq_chip,
- handle_level_irq);
- }
- giu_write(GIUINTSTATL, mask);
- } else if (pin < GIUINT_HIGH_MAX) {
- mask = 1 << (pin - GIUINT_HIGH_OFFSET);
- if (trigger != IRQ_TRIGGER_LEVEL) {
- giu_set(GIUINTTYPH, mask);
- if (signal == IRQ_SIGNAL_HOLD)
- giu_set(GIUINTHTSELH, mask);
- else
- giu_clear(GIUINTHTSELH, mask);
- if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
- switch (trigger) {
- case IRQ_TRIGGER_EDGE_FALLING:
- giu_set(GIUFEDGEINHH, mask);
- giu_clear(GIUREDGEINHH, mask);
- break;
- case IRQ_TRIGGER_EDGE_RISING:
- giu_clear(GIUFEDGEINHH, mask);
- giu_set(GIUREDGEINHH, mask);
- break;
- default:
- giu_set(GIUFEDGEINHH, mask);
- giu_set(GIUREDGEINHH, mask);
- break;
- }
- }
- set_irq_chip_and_handler(GIU_IRQ(pin),
- &giuint_high_irq_chip,
- handle_edge_irq);
- } else {
- giu_clear(GIUINTTYPH, mask);
- giu_clear(GIUINTHTSELH, mask);
- set_irq_chip_and_handler(GIU_IRQ(pin),
- &giuint_high_irq_chip,
- handle_level_irq);
- }
- giu_write(GIUINTSTATH, mask);
- }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
-
-void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
-{
- uint16_t mask;
-
- if (pin < GIUINT_HIGH_OFFSET) {
- mask = 1 << pin;
- if (level == IRQ_LEVEL_HIGH)
- giu_set(GIUINTALSELL, mask);
- else
- giu_clear(GIUINTALSELL, mask);
- giu_write(GIUINTSTATL, mask);
- } else if (pin < GIUINT_HIGH_MAX) {
- mask = 1 << (pin - GIUINT_HIGH_OFFSET);
- if (level == IRQ_LEVEL_HIGH)
- giu_set(GIUINTALSELH, mask);
- else
- giu_clear(GIUINTALSELH, mask);
- giu_write(GIUINTSTATH, mask);
- }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
-
-gpio_data_t vr41xx_gpio_get_pin(unsigned int pin)
-{
- uint16_t reg, mask;
-
- if (pin >= giu_nr_pins)
- return GPIO_DATA_INVAL;
-
- if (pin < 16) {
- reg = giu_read(GIUPIODL);
- mask = (uint16_t)1 << pin;
- } else if (pin < 32) {
- reg = giu_read(GIUPIODH);
- mask = (uint16_t)1 << (pin - 16);
- } else if (pin < 48) {
- reg = giu_read(GIUPODATL);
- mask = (uint16_t)1 << (pin - 32);
- } else {
- reg = giu_read(GIUPODATH);
- mask = (uint16_t)1 << (pin - 48);
- }
-
- if (reg & mask)
- return GPIO_DATA_HIGH;
-
- return GPIO_DATA_LOW;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin);
-
-int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data)
-{
- uint16_t offset, mask, reg;
- unsigned long flags;
-
- if (pin >= giu_nr_pins)
- return -EINVAL;
-
- if (pin < 16) {
- offset = GIUPIODL;
- mask = (uint16_t)1 << pin;
- } else if (pin < 32) {
- offset = GIUPIODH;
- mask = (uint16_t)1 << (pin - 16);
- } else if (pin < 48) {
- offset = GIUPODATL;
- mask = (uint16_t)1 << (pin - 32);
- } else {
- offset = GIUPODATH;
- mask = (uint16_t)1 << (pin - 48);
- }
-
- spin_lock_irqsave(&giu_lock, flags);
-
- reg = giu_read(offset);
- if (data == GPIO_DATA_HIGH)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(offset, reg);
-
- spin_unlock_irqrestore(&giu_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin);
-
-int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir)
-{
- uint16_t offset, mask, reg;
- unsigned long flags;
-
- if (pin >= giu_nr_pins)
- return -EINVAL;
-
- if (pin < 16) {
- offset = GIUIOSELL;
- mask = (uint16_t)1 << pin;
- } else if (pin < 32) {
- offset = GIUIOSELH;
- mask = (uint16_t)1 << (pin - 16);
- } else {
- if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
- offset = GIUPODATEN;
- mask = (uint16_t)1 << (pin - 32);
- } else {
- switch (pin) {
- case 48:
- offset = GIUPODATH;
- mask = PIOEN0;
- break;
- case 49:
- offset = GIUPODATH;
- mask = PIOEN1;
- break;
- default:
- return -EINVAL;
- }
- }
- }
-
- spin_lock_irqsave(&giu_lock, flags);
-
- reg = giu_read(offset);
- if (dir == GPIO_OUTPUT)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(offset, reg);
-
- spin_unlock_irqrestore(&giu_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction);
-
-int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
-{
- uint16_t reg, mask;
- unsigned long flags;
-
- if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
- return -EPERM;
-
- if (pin >= 15)
- return -EINVAL;
-
- mask = (uint16_t)1 << pin;
-
- spin_lock_irqsave(&giu_lock, flags);
-
- if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
- reg = giu_read(GIUTERMUPDN);
- if (pull == GPIO_PULL_UP)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(GIUTERMUPDN, reg);
-
- reg = giu_read(GIUUSEUPDN);
- reg |= mask;
- giu_write(GIUUSEUPDN, reg);
- } else {
- reg = giu_read(GIUUSEUPDN);
- reg &= ~mask;
- giu_write(GIUUSEUPDN, reg);
- }
-
- spin_unlock_irqrestore(&giu_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
-
-static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,
- loff_t *ppos)
-{
- unsigned int pin;
- char value = '0';
-
- pin = iminor(file->f_path.dentry->d_inode);
- if (pin >= giu_nr_pins)
- return -EBADF;
-
- if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH)
- value = '1';
-
- if (len <= 0)
- return -EFAULT;
-
- if (put_user(value, buf))
- return -EFAULT;
-
- return 1;
-}
-
-static ssize_t gpio_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
-{
- unsigned int pin;
- size_t i;
- char c;
- int retval = 0;
-
- pin = iminor(file->f_path.dentry->d_inode);
- if (pin >= giu_nr_pins)
- return -EBADF;
-
- for (i = 0; i < len; i++) {
- if (get_user(c, data + i))
- return -EFAULT;
-
- switch (c) {
- case '0':
- retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW);
- break;
- case '1':
- retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH);
- break;
- case 'D':
- printk(KERN_INFO "GPIO%d: pull down\n", pin);
- retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN);
- break;
- case 'd':
- printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
- retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
- break;
- case 'I':
- printk(KERN_INFO "GPIO%d: input\n", pin);
- retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT);
- break;
- case 'O':
- printk(KERN_INFO "GPIO%d: output\n", pin);
- retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT);
- break;
- case 'o':
- printk(KERN_INFO "GPIO%d: output disable\n", pin);
- retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE);
- break;
- case 'P':
- printk(KERN_INFO "GPIO%d: pull up\n", pin);
- retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP);
- break;
- case 'p':
- printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
- retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
- break;
- default:
- break;
- }
-
- if (retval < 0)
- break;
- }
-
- return i;
-}
-
-static int gpio_open(struct inode *inode, struct file *file)
-{
- unsigned int pin;
-
- cycle_kernel_lock();
- pin = iminor(inode);
- if (pin >= giu_nr_pins)
- return -EBADF;
-
- return nonseekable_open(inode, file);
-}
-
-static int gpio_release(struct inode *inode, struct file *file)
-{
- unsigned int pin;
-
- pin = iminor(inode);
- if (pin >= giu_nr_pins)
- return -EBADF;
-
- return 0;
-}
-
-static const struct file_operations gpio_fops = {
- .owner = THIS_MODULE,
- .read = gpio_read,
- .write = gpio_write,
- .open = gpio_open,
- .release = gpio_release,
-};
-
-static int __devinit giu_probe(struct platform_device *dev)
-{
- struct resource *res;
- unsigned int trigger, i, pin;
- struct irq_chip *chip;
- int irq, retval;
-
- switch (dev->id) {
- case GPIO_50PINS_PULLUPDOWN:
- giu_flags = GPIO_HAS_PULLUPDOWN_IO;
- giu_nr_pins = 50;
- break;
- case GPIO_36PINS:
- giu_nr_pins = 36;
- break;
- case GPIO_48PINS_EDGE_SELECT:
- giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
- giu_nr_pins = 48;
- break;
- default:
- printk(KERN_ERR "GIU: unknown ID %d\n", dev->id);
- return -ENODEV;
- }
-
- res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res)
- return -EBUSY;
-
- giu_base = ioremap(res->start, res->end - res->start + 1);
- if (!giu_base)
- return -ENOMEM;
-
- retval = register_chrdev(major, "GIU", &gpio_fops);
- if (retval < 0) {
- iounmap(giu_base);
- giu_base = NULL;
- return retval;
- }
-
- if (major == 0) {
- major = retval;
- printk(KERN_INFO "GIU: major number %d\n", major);
- }
-
- spin_lock_init(&giu_lock);
-
- giu_write(GIUINTENL, 0);
- giu_write(GIUINTENH, 0);
-
- trigger = giu_read(GIUINTTYPH) << 16;
- trigger |= giu_read(GIUINTTYPL);
- for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
- pin = GPIO_PIN_OF_IRQ(i);
- if (pin < GIUINT_HIGH_OFFSET)
- chip = &giuint_low_irq_chip;
- else
- chip = &giuint_high_irq_chip;
-
- if (trigger & (1 << pin))
- set_irq_chip_and_handler(i, chip, handle_edge_irq);
- else
- set_irq_chip_and_handler(i, chip, handle_level_irq);
-
- }
-
- irq = platform_get_irq(dev, 0);
- if (irq < 0 || irq >= nr_irqs)
- return -EBUSY;
-
- return cascade_irq(irq, giu_get_irq);
-}
-
-static int __devexit giu_remove(struct platform_device *dev)
-{
- if (giu_base) {
- iounmap(giu_base);
- giu_base = NULL;
- }
-
- return 0;
-}
-
-static struct platform_driver giu_device_driver = {
- .probe = giu_probe,
- .remove = __devexit_p(giu_remove),
- .driver = {
- .name = "GIU",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init vr41xx_giu_init(void)
-{
- return platform_driver_register(&giu_device_driver);
-}
-
-static void __exit vr41xx_giu_exit(void)
-{
- platform_driver_unregister(&giu_device_driver);
-}
-
-module_init(vr41xx_giu_init);
-module_exit(vr41xx_giu_exit);
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index 9ffb05f4095..93c2322feab 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -161,7 +161,7 @@ static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
if (periodic)
sh_tmu_write(p, TCOR, delta);
else
- sh_tmu_write(p, TCOR, 0);
+ sh_tmu_write(p, TCOR, 0xffffffff);
sh_tmu_write(p, TCNT, delta);
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index c5afc98e267..85e5dc0431f 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -202,9 +202,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
* cn_proc_mcast_ctl
* @data: message sent from userspace via the connector
*/
-static void cn_proc_mcast_ctl(void *data)
+static void cn_proc_mcast_ctl(struct cn_msg *msg)
{
- struct cn_msg *msg = data;
enum proc_cn_mcast_op *mc_op = NULL;
int err = 0;
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
index 408c2af25d5..4a1dfe1f4ba 100644
--- a/drivers/connector/cn_queue.c
+++ b/drivers/connector/cn_queue.c
@@ -87,7 +87,9 @@ void cn_queue_wrapper(struct work_struct *work)
kfree(d->free);
}
-static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struct cb_id *id, void (*callback)(void *))
+static struct cn_callback_entry *
+cn_queue_alloc_callback_entry(char *name, struct cb_id *id,
+ void (*callback)(struct cn_msg *))
{
struct cn_callback_entry *cbq;
@@ -120,7 +122,8 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
return ((i1->idx == i2->idx) && (i1->val == i2->val));
}
-int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *))
+int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id,
+ void (*callback)(struct cn_msg *))
{
struct cn_callback_entry *cbq, *__cbq;
int found = 0;
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index 08b2500f21e..74f52af7956 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -269,7 +269,8 @@ static void cn_notify(struct cb_id *id, u32 notify_event)
*
* May sleep.
*/
-int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))
+int cn_add_callback(struct cb_id *id, char *name,
+ void (*callback)(struct cn_msg *))
{
int err;
struct cn_dev *dev = &cdev;
@@ -351,9 +352,8 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
*
* Used for notification of a request's processing.
*/
-static void cn_callback(void *data)
+static void cn_callback(struct cn_msg *msg)
{
- struct cn_msg *msg = data;
struct cn_ctl_msg *ctl;
struct cn_ctl_entry *ent;
u32 size;
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index c36bf40568c..858fe603722 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -754,13 +754,13 @@ static void amd64_cpu_display_info(struct amd64_pvt *pvt)
static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
{
int bit;
- enum dev_type edac_cap = EDAC_NONE;
+ enum dev_type edac_cap = EDAC_FLAG_NONE;
bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= OPTERON_CPU_REV_F)
? 19
: 17;
- if (pvt->dclr0 >> BIT(bit))
+ if (pvt->dclr0 & BIT(bit))
edac_cap = EDAC_FLAG_SECDED;
return edac_cap;
@@ -1269,7 +1269,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
if (channels == 0)
channels = 1;
- debugf0("DIMM count= %d\n", channels);
+ debugf0("MCT channel count: %d\n", channels);
return channels;
@@ -2966,7 +2966,12 @@ static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
" Use of the override can cause "
"unknown side effects.\n");
ret = -ENODEV;
- }
+ } else
+ /*
+ * enable further driver loading if ECC enable is
+ * overridden.
+ */
+ ret = 0;
} else {
amd64_printk(KERN_INFO,
"ECC is enabled by BIOS, Proceeding "
@@ -3006,7 +3011,6 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
mci->mtype_cap = MEM_FLAG_DDR2 | MEM_FLAG_RDDR2;
mci->edac_ctl_cap = EDAC_FLAG_NONE;
- mci->edac_cap = EDAC_FLAG_NONE;
if (pvt->nbcap & K8_NBCAP_SECDED)
mci->edac_ctl_cap |= EDAC_FLAG_SECDED;
@@ -3052,7 +3056,7 @@ static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl,
if (!pvt)
goto err_exit;
- pvt->mc_node_id = get_mc_node_id_from_pdev(dram_f2_ctl);
+ pvt->mc_node_id = get_node_id(dram_f2_ctl);
pvt->dram_f2_ctl = dram_f2_ctl;
pvt->ext_model = boot_cpu_data.x86_model >> 4;
@@ -3179,8 +3183,7 @@ static int __devinit amd64_init_one_instance(struct pci_dev *pdev,
{
int ret = 0;
- debugf0("(MC node=%d,mc_type='%s')\n",
- get_mc_node_id_from_pdev(pdev),
+ debugf0("(MC node=%d,mc_type='%s')\n", get_node_id(pdev),
get_amd_family_name(mc_type->driver_data));
ret = pci_enable_device(pdev);
@@ -3319,15 +3322,17 @@ static int __init amd64_edac_init(void)
err = amd64_init_2nd_stage(pvt_lookup[nb]);
if (err)
- goto err_exit;
+ goto err_2nd_stage;
}
amd64_setup_pci_device();
return 0;
+err_2nd_stage:
+ debugf0("2nd stage failed\n");
+
err_exit:
- debugf0("'finish_setup' stage failed\n");
pci_unregister_driver(&amd64_pci_driver);
return err;
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index a159957e167..ba73015af8e 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -444,7 +444,7 @@ enum {
#define K8_MSR_MC4ADDR 0x0412
/* AMD sets the first MC device at device ID 0x18. */
-static inline int get_mc_node_id_from_pdev(struct pci_dev *pdev)
+static inline int get_node_id(struct pci_dev *pdev)
{
return PCI_SLOT(pdev->devfn) - 0x18;
}
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index 3493c6bdb82..871c13b4c14 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -150,6 +150,8 @@ enum mem_type {
MEM_FB_DDR2, /* fully buffered DDR2 */
MEM_RDDR2, /* Registered DDR2 RAM */
MEM_XDR, /* Rambus XDR */
+ MEM_DDR3, /* DDR3 RAM */
+ MEM_RDDR3, /* Registered DDR3 RAM */
};
#define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
@@ -167,6 +169,8 @@ enum mem_type {
#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
#define MEM_FLAG_XDR BIT(MEM_XDR)
+#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
+#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
/* chipset Error Detection and Correction capabilities and mode */
enum edac_type {
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index ad218fe4942..e1d4ce08348 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -94,7 +94,9 @@ static const char *mem_types[] = {
[MEM_DDR2] = "Unbuffered-DDR2",
[MEM_FB_DDR2] = "FullyBuffered-DDR2",
[MEM_RDDR2] = "Registered-DDR2",
- [MEM_XDR] = "XDR"
+ [MEM_XDR] = "XDR",
+ [MEM_DDR3] = "Unbuffered-DDR3",
+ [MEM_RDDR3] = "Registered-DDR3"
};
static const char *dev_types[] = {
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 7c8c2d72916..3f2ccfc6407 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -757,6 +757,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
case DSC_SDTYPE_DDR2:
mtype = MEM_RDDR2;
break;
+ case DSC_SDTYPE_DDR3:
+ mtype = MEM_RDDR3;
+ break;
default:
mtype = MEM_UNKNOWN;
break;
@@ -769,6 +772,9 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
case DSC_SDTYPE_DDR2:
mtype = MEM_DDR2;
break;
+ case DSC_SDTYPE_DDR3:
+ mtype = MEM_DDR3;
+ break;
default:
mtype = MEM_UNKNOWN;
break;
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 135b3539a03..52432ee7c4b 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -53,6 +53,7 @@
#define DSC_SDTYPE_DDR 0x02000000
#define DSC_SDTYPE_DDR2 0x03000000
+#define DSC_SDTYPE_DDR3 0x07000000
#define DSC_X32_EN 0x00000020
/* Err_Int_En */
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 3582c39f972..96dda81c922 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -79,6 +79,12 @@ config GPIO_XILINX
help
Say yes here to support the Xilinx FPGA GPIO device
+config GPIO_VR41XX
+ tristate "NEC VR4100 series General-purpose I/O Uint support"
+ depends on CPU_VR41XX
+ help
+ Say yes here to support the NEC VR4100 series General-purpose I/O Uint
+
comment "I2C GPIO expanders:"
config GPIO_MAX732X
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index ef90203e8f3..9244c6fcd8b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_GPIO_PL061) += pl061.o
obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o
obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o
obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o
+obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c
index aa8e7cb020d..4ee4c8367a3 100644
--- a/drivers/gpio/pl061.c
+++ b/drivers/gpio/pl061.c
@@ -109,6 +109,16 @@ static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
writeb(!!value << offset, chip->base + (1 << (offset + 2)));
}
+static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
+
+ if (chip->irq_base == (unsigned) -1)
+ return -EINVAL;
+
+ return chip->irq_base + offset;
+}
+
/*
* PL061 GPIO IRQ
*/
@@ -200,7 +210,7 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
desc->chip->ack(irq);
list_for_each(ptr, chip_list) {
unsigned long pending;
- int gpio;
+ int offset;
chip = list_entry(ptr, struct pl061_gpio, list);
pending = readb(chip->base + GPIOMIS);
@@ -209,8 +219,8 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
if (pending == 0)
continue;
- for_each_bit(gpio, &pending, PL061_GPIO_NR)
- generic_handle_irq(gpio_to_irq(gpio));
+ for_each_bit(offset, &pending, PL061_GPIO_NR)
+ generic_handle_irq(pl061_to_irq(&chip->gc, offset));
}
desc->chip->unmask(irq);
}
@@ -221,7 +231,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
struct pl061_gpio *chip;
struct list_head *chip_list;
int ret, irq, i;
- static unsigned long init_irq[BITS_TO_LONGS(NR_IRQS)];
+ static DECLARE_BITMAP(init_irq, NR_IRQS);
pdata = dev->dev.platform_data;
if (pdata == NULL)
@@ -251,6 +261,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
chip->gc.set = pl061_set_value;
+ chip->gc.to_irq = pl061_to_irq;
chip->gc.base = pdata->gpio_base;
chip->gc.ngpio = PL061_GPIO_NR;
chip->gc.label = dev_name(&dev->dev);
@@ -280,6 +291,7 @@ static int __init pl061_probe(struct amba_device *dev, struct amba_id *id)
if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */
chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL);
if (chip_list == NULL) {
+ clear_bit(irq, init_irq);
ret = -ENOMEM;
goto iounmap;
}
diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c
new file mode 100644
index 00000000000..b70e06133e7
--- /dev/null
+++ b/drivers/gpio/vr41xx_giu.c
@@ -0,0 +1,586 @@
+/*
+ * Driver for NEC VR4100 series General-purpose I/O Unit.
+ *
+ * Copyright (C) 2002 MontaVista Software Inc.
+ * Author: Yoichi Yuasa <source@mvista.com>
+ * Copyright (C) 2003-2009 Yoichi Yuasa <yuasa@linux-mips.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/vr41xx/giu.h>
+#include <asm/vr41xx/irq.h>
+#include <asm/vr41xx/vr41xx.h>
+
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
+MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
+MODULE_LICENSE("GPL");
+
+#define GIUIOSELL 0x00
+#define GIUIOSELH 0x02
+#define GIUPIODL 0x04
+#define GIUPIODH 0x06
+#define GIUINTSTATL 0x08
+#define GIUINTSTATH 0x0a
+#define GIUINTENL 0x0c
+#define GIUINTENH 0x0e
+#define GIUINTTYPL 0x10
+#define GIUINTTYPH 0x12
+#define GIUINTALSELL 0x14
+#define GIUINTALSELH 0x16
+#define GIUINTHTSELL 0x18
+#define GIUINTHTSELH 0x1a
+#define GIUPODATL 0x1c
+#define GIUPODATEN 0x1c
+#define GIUPODATH 0x1e
+ #define PIOEN0 0x0100
+ #define PIOEN1 0x0200
+#define GIUPODAT 0x1e
+#define GIUFEDGEINHL 0x20
+#define GIUFEDGEINHH 0x22
+#define GIUREDGEINHL 0x24
+#define GIUREDGEINHH 0x26
+
+#define GIUUSEUPDN 0x1e0
+#define GIUTERMUPDN 0x1e2
+
+#define GPIO_HAS_PULLUPDOWN_IO 0x0001
+#define GPIO_HAS_OUTPUT_ENABLE 0x0002
+#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
+
+enum {
+ GPIO_INPUT,
+ GPIO_OUTPUT,
+};
+
+static DEFINE_SPINLOCK(giu_lock);
+static unsigned long giu_flags;
+
+static void __iomem *giu_base;
+
+#define giu_read(offset) readw(giu_base + (offset))
+#define giu_write(offset, value) writew((value), giu_base + (offset))
+
+#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE)
+#define GIUINT_HIGH_OFFSET 16
+#define GIUINT_HIGH_MAX 32
+
+static inline u16 giu_set(u16 offset, u16 set)
+{
+ u16 data;
+
+ data = giu_read(offset);
+ data |= set;
+ giu_write(offset, data);
+
+ return data;
+}
+
+static inline u16 giu_clear(u16 offset, u16 clear)
+{
+ u16 data;
+
+ data = giu_read(offset);
+ data &= ~clear;
+ giu_write(offset, data);
+
+ return data;
+}
+
+static void ack_giuint_low(unsigned int irq)
+{
+ giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static void mask_giuint_low(unsigned int irq)
+{
+ giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static void mask_ack_giuint_low(unsigned int irq)
+{
+ unsigned int pin;
+
+ pin = GPIO_PIN_OF_IRQ(irq);
+ giu_clear(GIUINTENL, 1 << pin);
+ giu_write(GIUINTSTATL, 1 << pin);
+}
+
+static void unmask_giuint_low(unsigned int irq)
+{
+ giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
+}
+
+static struct irq_chip giuint_low_irq_chip = {
+ .name = "GIUINTL",
+ .ack = ack_giuint_low,
+ .mask = mask_giuint_low,
+ .mask_ack = mask_ack_giuint_low,
+ .unmask = unmask_giuint_low,
+};
+
+static void ack_giuint_high(unsigned int irq)
+{
+ giu_write(GIUINTSTATH,
+ 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static void mask_giuint_high(unsigned int irq)
+{
+ giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static void mask_ack_giuint_high(unsigned int irq)
+{
+ unsigned int pin;
+
+ pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
+ giu_clear(GIUINTENH, 1 << pin);
+ giu_write(GIUINTSTATH, 1 << pin);
+}
+
+static void unmask_giuint_high(unsigned int irq)
+{
+ giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
+}
+
+static struct irq_chip giuint_high_irq_chip = {
+ .name = "GIUINTH",
+ .ack = ack_giuint_high,
+ .mask = mask_giuint_high,
+ .mask_ack = mask_ack_giuint_high,
+ .unmask = unmask_giuint_high,
+};
+
+static int giu_get_irq(unsigned int irq)
+{
+ u16 pendl, pendh, maskl, maskh;
+ int i;
+
+ pendl = giu_read(GIUINTSTATL);
+ pendh = giu_read(GIUINTSTATH);
+ maskl = giu_read(GIUINTENL);
+ maskh = giu_read(GIUINTENH);
+
+ maskl &= pendl;
+ maskh &= pendh;
+
+ if (maskl) {
+ for (i = 0; i < 16; i++) {
+ if (maskl & (1 << i))
+ return GIU_IRQ(i);
+ }
+ } else if (maskh) {
+ for (i = 0; i < 16; i++) {
+ if (maskh & (1 << i))
+ return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
+ }
+ }
+
+ printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
+ maskl, pendl, maskh, pendh);
+
+ atomic_inc(&irq_err_count);
+
+ return -EINVAL;
+}
+
+void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger,
+ irq_signal_t signal)
+{
+ u16 mask;
+
+ if (pin < GIUINT_HIGH_OFFSET) {
+ mask = 1 << pin;
+ if (trigger != IRQ_TRIGGER_LEVEL) {
+ giu_set(GIUINTTYPL, mask);
+ if (signal == IRQ_SIGNAL_HOLD)
+ giu_set(GIUINTHTSELL, mask);
+ else
+ giu_clear(GIUINTHTSELL, mask);
+ if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
+ switch (trigger) {
+ case IRQ_TRIGGER_EDGE_FALLING:
+ giu_set(GIUFEDGEINHL, mask);
+ giu_clear(GIUREDGEINHL, mask);
+ break;
+ case IRQ_TRIGGER_EDGE_RISING:
+ giu_clear(GIUFEDGEINHL, mask);
+ giu_set(GIUREDGEINHL, mask);
+ break;
+ default:
+ giu_set(GIUFEDGEINHL, mask);
+ giu_set(GIUREDGEINHL, mask);
+ break;
+ }
+ }
+ set_irq_chip_and_handler(GIU_IRQ(pin),
+ &giuint_low_irq_chip,
+ handle_edge_irq);
+ } else {
+ giu_clear(GIUINTTYPL, mask);
+ giu_clear(GIUINTHTSELL, mask);
+ set_irq_chip_and_handler(GIU_IRQ(pin),
+ &giuint_low_irq_chip,
+ handle_level_irq);
+ }
+ giu_write(GIUINTSTATL, mask);
+ } else if (pin < GIUINT_HIGH_MAX) {
+ mask = 1 << (pin - GIUINT_HIGH_OFFSET);
+ if (trigger != IRQ_TRIGGER_LEVEL) {
+ giu_set(GIUINTTYPH, mask);
+ if (signal == IRQ_SIGNAL_HOLD)
+ giu_set(GIUINTHTSELH, mask);
+ else
+ giu_clear(GIUINTHTSELH, mask);
+ if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
+ switch (trigger) {
+ case IRQ_TRIGGER_EDGE_FALLING:
+ giu_set(GIUFEDGEINHH, mask);
+ giu_clear(GIUREDGEINHH, mask);
+ break;
+ case IRQ_TRIGGER_EDGE_RISING:
+ giu_clear(GIUFEDGEINHH, mask);
+ giu_set(GIUREDGEINHH, mask);
+ break;
+ default:
+ giu_set(GIUFEDGEINHH, mask);
+ giu_set(GIUREDGEINHH, mask);
+ break;
+ }
+ }
+ set_irq_chip_and_handler(GIU_IRQ(pin),
+ &giuint_high_irq_chip,
+ handle_edge_irq);
+ } else {
+ giu_clear(GIUINTTYPH, mask);
+ giu_clear(GIUINTHTSELH, mask);
+ set_irq_chip_and_handler(GIU_IRQ(pin),
+ &giuint_high_irq_chip,
+ handle_level_irq);
+ }
+ giu_write(GIUINTSTATH, mask);
+ }
+}
+EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
+
+void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
+{
+ u16 mask;
+
+ if (pin < GIUINT_HIGH_OFFSET) {
+ mask = 1 << pin;
+ if (level == IRQ_LEVEL_HIGH)
+ giu_set(GIUINTALSELL, mask);
+ else
+ giu_clear(GIUINTALSELL, mask);
+ giu_write(GIUINTSTATL, mask);
+ } else if (pin < GIUINT_HIGH_MAX) {
+ mask = 1 << (pin - GIUINT_HIGH_OFFSET);
+ if (level == IRQ_LEVEL_HIGH)
+ giu_set(GIUINTALSELH, mask);
+ else
+ giu_clear(GIUINTALSELH, mask);
+ giu_write(GIUINTSTATH, mask);
+ }
+}
+EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
+
+static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir)
+{
+ u16 offset, mask, reg;
+ unsigned long flags;
+
+ if (pin >= chip->ngpio)
+ return -EINVAL;
+
+ if (pin < 16) {
+ offset = GIUIOSELL;
+ mask = 1 << pin;
+ } else if (pin < 32) {
+ offset = GIUIOSELH;
+ mask = 1 << (pin - 16);
+ } else {
+ if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
+ offset = GIUPODATEN;
+ mask = 1 << (pin - 32);
+ } else {
+ switch (pin) {
+ case 48:
+ offset = GIUPODATH;
+ mask = PIOEN0;
+ break;
+ case 49:
+ offset = GIUPODATH;
+ mask = PIOEN1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ }
+
+ spin_lock_irqsave(&giu_lock, flags);
+
+ reg = giu_read(offset);
+ if (dir == GPIO_OUTPUT)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ giu_write(offset, reg);
+
+ spin_unlock_irqrestore(&giu_lock, flags);
+
+ return 0;
+}
+
+int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
+{
+ u16 reg, mask;
+ unsigned long flags;
+
+ if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
+ return -EPERM;
+
+ if (pin >= 15)
+ return -EINVAL;
+
+ mask = 1 << pin;
+
+ spin_lock_irqsave(&giu_lock, flags);
+
+ if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
+ reg = giu_read(GIUTERMUPDN);
+ if (pull == GPIO_PULL_UP)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ giu_write(GIUTERMUPDN, reg);
+
+ reg = giu_read(GIUUSEUPDN);
+ reg |= mask;
+ giu_write(GIUUSEUPDN, reg);
+ } else {
+ reg = giu_read(GIUUSEUPDN);
+ reg &= ~mask;
+ giu_write(GIUUSEUPDN, reg);
+ }
+
+ spin_unlock_irqrestore(&giu_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
+
+static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin)
+{
+ u16 reg, mask;
+
+ if (pin >= chip->ngpio)
+ return -EINVAL;
+
+ if (pin < 16) {
+ reg = giu_read(GIUPIODL);
+ mask = 1 << pin;
+ } else if (pin < 32) {
+ reg = giu_read(GIUPIODH);
+ mask = 1 << (pin - 16);
+ } else if (pin < 48) {
+ reg = giu_read(GIUPODATL);
+ mask = 1 << (pin - 32);
+ } else {
+ reg = giu_read(GIUPODATH);
+ mask = 1 << (pin - 48);
+ }
+
+ if (reg & mask)
+ return 1;
+
+ return 0;
+}
+
+static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin,
+ int value)
+{
+ u16 offset, mask, reg;
+ unsigned long flags;
+
+ if (pin >= chip->ngpio)
+ return;
+
+ if (pin < 16) {
+ offset = GIUPIODL;
+ mask = 1 << pin;
+ } else if (pin < 32) {
+ offset = GIUPIODH;
+ mask = 1 << (pin - 16);
+ } else if (pin < 48) {
+ offset = GIUPODATL;
+ mask = 1 << (pin - 32);
+ } else {
+ offset = GIUPODATH;
+ mask = 1 << (pin - 48);
+ }
+
+ spin_lock_irqsave(&giu_lock, flags);
+
+ reg = giu_read(offset);
+ if (value)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ giu_write(offset, reg);
+
+ spin_unlock_irqrestore(&giu_lock, flags);
+}
+
+
+static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ return giu_set_direction(chip, offset, GPIO_INPUT);
+}
+
+static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ vr41xx_gpio_set(chip, offset, value);
+
+ return giu_set_direction(chip, offset, GPIO_OUTPUT);
+}
+
+static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ if (offset >= chip->ngpio)
+ return -EINVAL;
+
+ return GIU_IRQ_BASE + offset;
+}
+
+static struct gpio_chip vr41xx_gpio_chip = {
+ .label = "vr41xx",
+ .owner = THIS_MODULE,
+ .direction_input = vr41xx_gpio_direction_input,
+ .get = vr41xx_gpio_get,
+ .direction_output = vr41xx_gpio_direction_output,
+ .set = vr41xx_gpio_set,
+ .to_irq = vr41xx_gpio_to_irq,
+};
+
+static int __devinit giu_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ unsigned int trigger, i, pin;
+ struct irq_chip *chip;
+ int irq, retval;
+
+ switch (pdev->id) {
+ case GPIO_50PINS_PULLUPDOWN:
+ giu_flags = GPIO_HAS_PULLUPDOWN_IO;
+ vr41xx_gpio_chip.ngpio = 50;
+ break;
+ case GPIO_36PINS:
+ vr41xx_gpio_chip.ngpio = 36;
+ break;
+ case GPIO_48PINS_EDGE_SELECT:
+ giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
+ vr41xx_gpio_chip.ngpio = 48;
+ break;
+ default:
+ dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id);
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EBUSY;
+
+ giu_base = ioremap(res->start, res->end - res->start + 1);
+ if (!giu_base)
+ return -ENOMEM;
+
+ vr41xx_gpio_chip.dev = &pdev->dev;
+
+ retval = gpiochip_add(&vr41xx_gpio_chip);
+
+ giu_write(GIUINTENL, 0);
+ giu_write(GIUINTENH, 0);
+
+ trigger = giu_read(GIUINTTYPH) << 16;
+ trigger |= giu_read(GIUINTTYPL);
+ for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
+ pin = GPIO_PIN_OF_IRQ(i);
+ if (pin < GIUINT_HIGH_OFFSET)
+ chip = &giuint_low_irq_chip;
+ else
+ chip = &giuint_high_irq_chip;
+
+ if (trigger & (1 << pin))
+ set_irq_chip_and_handler(i, chip, handle_edge_irq);
+ else
+ set_irq_chip_and_handler(i, chip, handle_level_irq);
+
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0 || irq >= nr_irqs)
+ return -EBUSY;
+
+ return cascade_irq(irq, giu_get_irq);
+}
+
+static int __devexit giu_remove(struct platform_device *pdev)
+{
+ if (giu_base) {
+ iounmap(giu_base);
+ giu_base = NULL;
+ }
+
+ return 0;
+}
+
+static struct platform_driver giu_device_driver = {
+ .probe = giu_probe,
+ .remove = __devexit_p(giu_remove),
+ .driver = {
+ .name = "GIU",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init vr41xx_giu_init(void)
+{
+ return platform_driver_register(&giu_device_driver);
+}
+
+static void __exit vr41xx_giu_exit(void)
+{
+ platform_driver_unregister(&giu_device_driver);
+}
+
+module_init(vr41xx_giu_init);
+module_exit(vr41xx_giu_exit);
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c961fe415ae..39b393d38bb 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -81,6 +81,7 @@ config DRM_I830
config DRM_I915
tristate "i915 driver"
+ depends on AGP_INTEL
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 4e89ab08b7b..fe23f29f7cb 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -16,6 +16,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm-$(CONFIG_COMPAT) += drm_ioc32.o
obj-$(CONFIG_DRM) += drm.o
+obj-$(CONFIG_DRM_TTM) += ttm/
obj-$(CONFIG_DRM_TDFX) += tdfx/
obj-$(CONFIG_DRM_R128) += r128/
obj-$(CONFIG_DRM_RADEON)+= radeon/
@@ -26,4 +27,3 @@ obj-$(CONFIG_DRM_I915) += i915/
obj-$(CONFIG_DRM_SIS) += sis/
obj-$(CONFIG_DRM_SAVAGE)+= savage/
obj-$(CONFIG_DRM_VIA) +=via/
-obj-$(CONFIG_DRM_TTM) += ttm/
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 7d0835226f6..80cc6d06d61 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -294,10 +294,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo;
unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo;
unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo;
- unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 8 | pt->hsync_offset_lo;
- unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 6 | pt->hsync_pulse_width_lo;
- unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) | (pt->vsync_offset_pulse_width_lo & 0xf);
- unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) >> 2 | pt->vsync_offset_pulse_width_lo >> 4;
+ unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) << 2 | pt->hsync_offset_lo;
+ unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) << 4 | pt->hsync_pulse_width_lo;
+ unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) >> 2 | pt->vsync_offset_pulse_width_lo >> 4;
+ unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 4 | (pt->vsync_offset_pulse_width_lo & 0xf);
/* ignore tiny modes */
if (hactive < 64 || vactive < 64)
@@ -347,8 +347,8 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ?
DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
- mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
- mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
+ mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4;
+ mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf) << 8;
if (quirks & EDID_QUIRK_DETAILED_IN_CM) {
mode->width_mm *= 10;
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 51c5a050aa7..30d6b99fb30 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -13,6 +13,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
intel_crt.o \
intel_lvds.o \
intel_bios.o \
+ intel_dp.o \
+ intel_dp_i2c.o \
intel_hdmi.o \
intel_sdvo.o \
intel_modes.o \
diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h
index e747ac42fe3..288fc50627e 100644
--- a/drivers/gpu/drm/i915/dvo.h
+++ b/drivers/gpu/drm/i915/dvo.h
@@ -37,7 +37,7 @@ struct intel_dvo_device {
/* GPIO register used for i2c bus to control this device */
u32 gpio;
int slave_addr;
- struct intel_i2c_chan *i2c_bus;
+ struct i2c_adapter *i2c_bus;
const struct intel_dvo_dev_ops *dev_ops;
void *dev_priv;
@@ -52,7 +52,7 @@ struct intel_dvo_dev_ops {
* Returns NULL if the device does not exist.
*/
bool (*init)(struct intel_dvo_device *dvo,
- struct intel_i2c_chan *i2cbus);
+ struct i2c_adapter *i2cbus);
/*
* Called to allow the output a chance to create properties after the
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
index 03d4b4973b0..621815b531d 100644
--- a/drivers/gpu/drm/i915/dvo_ch7017.c
+++ b/drivers/gpu/drm/i915/dvo_ch7017.c
@@ -176,19 +176,20 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
{
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
struct i2c_msg msgs[] = {
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 1,
.buf = out_buf,
},
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = I2C_M_RD,
.len = 1,
.buf = in_buf,
@@ -208,10 +209,11 @@ static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
{
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 2,
.buf = out_buf,
@@ -228,8 +230,9 @@ static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
/** Probes for a CH7017 on the given bus and slave address. */
static bool ch7017_init(struct intel_dvo_device *dvo,
- struct intel_i2c_chan *i2cbus)
+ struct i2c_adapter *adapter)
{
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
struct ch7017_priv *priv;
uint8_t val;
@@ -237,8 +240,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
if (priv == NULL)
return false;
- dvo->i2c_bus = i2cbus;
- dvo->i2c_bus->slave_addr = dvo->slave_addr;
+ dvo->i2c_bus = adapter;
dvo->dev_priv = priv;
if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
@@ -248,7 +250,7 @@ static bool ch7017_init(struct intel_dvo_device *dvo,
val != CH7018_DEVICE_ID_VALUE &&
val != CH7019_DEVICE_ID_VALUE) {
DRM_DEBUG("ch701x not detected, got %d: from %s Slave %d.\n",
- val, i2cbus->adapter.name,i2cbus->slave_addr);
+ val, i2cbus->adapter.name,dvo->slave_addr);
goto fail;
}
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
index d2fd95dbd03..a9b89628968 100644
--- a/drivers/gpu/drm/i915/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c
@@ -123,19 +123,20 @@ static char *ch7xxx_get_id(uint8_t vid)
static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
struct i2c_msg msgs[] = {
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 1,
.buf = out_buf,
},
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = I2C_M_RD,
.len = 1,
.buf = in_buf,
@@ -152,7 +153,7 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
if (!ch7xxx->quiet) {
DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
- addr, i2cbus->adapter.name, i2cbus->slave_addr);
+ addr, i2cbus->adapter.name, dvo->slave_addr);
}
return false;
}
@@ -161,10 +162,11 @@ static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 2,
.buf = out_buf,
@@ -178,14 +180,14 @@ static bool ch7xxx_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
if (!ch7xxx->quiet) {
DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
- addr, i2cbus->adapter.name, i2cbus->slave_addr);
+ addr, i2cbus->adapter.name, dvo->slave_addr);
}
return false;
}
static bool ch7xxx_init(struct intel_dvo_device *dvo,
- struct intel_i2c_chan *i2cbus)
+ struct i2c_adapter *adapter)
{
/* this will detect the CH7xxx chip on the specified i2c bus */
struct ch7xxx_priv *ch7xxx;
@@ -196,8 +198,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
if (ch7xxx == NULL)
return false;
- dvo->i2c_bus = i2cbus;
- dvo->i2c_bus->slave_addr = dvo->slave_addr;
+ dvo->i2c_bus = adapter;
dvo->dev_priv = ch7xxx;
ch7xxx->quiet = true;
@@ -207,7 +208,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
name = ch7xxx_get_id(vendor);
if (!name) {
DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
- vendor, i2cbus->adapter.name, i2cbus->slave_addr);
+ vendor, adapter->name, dvo->slave_addr);
goto out;
}
@@ -217,7 +218,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
if (device != CH7xxx_DID) {
DRM_DEBUG("ch7xxx not detected; got 0x%02x from %s slave %d.\n",
- vendor, i2cbus->adapter.name, i2cbus->slave_addr);
+ vendor, adapter->name, dvo->slave_addr);
goto out;
}
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
index 0c8d375e8e3..aa176f9921f 100644
--- a/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/dvo_ivch.c
@@ -169,13 +169,14 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo);
static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
{
struct ivch_priv *priv = dvo->dev_priv;
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[1];
u8 in_buf[2];
struct i2c_msg msgs[] = {
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = I2C_M_RD,
.len = 0,
},
@@ -186,7 +187,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
.buf = out_buf,
},
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = I2C_M_RD | I2C_M_NOSTART,
.len = 2,
.buf = in_buf,
@@ -202,7 +203,7 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
if (!priv->quiet) {
DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
- addr, i2cbus->adapter.name, i2cbus->slave_addr);
+ addr, i2cbus->adapter.name, dvo->slave_addr);
}
return false;
}
@@ -211,10 +212,11 @@ static bool ivch_read(struct intel_dvo_device *dvo, int addr, uint16_t *data)
static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
{
struct ivch_priv *priv = dvo->dev_priv;
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[3];
struct i2c_msg msg = {
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 3,
.buf = out_buf,
@@ -229,7 +231,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
if (!priv->quiet) {
DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
- addr, i2cbus->adapter.name, i2cbus->slave_addr);
+ addr, i2cbus->adapter.name, dvo->slave_addr);
}
return false;
@@ -237,7 +239,7 @@ static bool ivch_write(struct intel_dvo_device *dvo, int addr, uint16_t data)
/** Probes the given bus and slave address for an ivch */
static bool ivch_init(struct intel_dvo_device *dvo,
- struct intel_i2c_chan *i2cbus)
+ struct i2c_adapter *adapter)
{
struct ivch_priv *priv;
uint16_t temp;
@@ -246,8 +248,7 @@ static bool ivch_init(struct intel_dvo_device *dvo,
if (priv == NULL)
return false;
- dvo->i2c_bus = i2cbus;
- dvo->i2c_bus->slave_addr = dvo->slave_addr;
+ dvo->i2c_bus = adapter;
dvo->dev_priv = priv;
priv->quiet = true;
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c
index 033a4bb070b..e1c1f7341e5 100644
--- a/drivers/gpu/drm/i915/dvo_sil164.c
+++ b/drivers/gpu/drm/i915/dvo_sil164.c
@@ -76,19 +76,20 @@ struct sil164_priv {
static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct sil164_priv *sil = dvo->dev_priv;
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
struct i2c_msg msgs[] = {
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 1,
.buf = out_buf,
},
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = I2C_M_RD,
.len = 1,
.buf = in_buf,
@@ -105,7 +106,7 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
if (!sil->quiet) {
DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
- addr, i2cbus->adapter.name, i2cbus->slave_addr);
+ addr, i2cbus->adapter.name, dvo->slave_addr);
}
return false;
}
@@ -113,10 +114,11 @@ static bool sil164_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct sil164_priv *sil= dvo->dev_priv;
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 2,
.buf = out_buf,
@@ -130,7 +132,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
if (!sil->quiet) {
DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
- addr, i2cbus->adapter.name, i2cbus->slave_addr);
+ addr, i2cbus->adapter.name, dvo->slave_addr);
}
return false;
@@ -138,7 +140,7 @@ static bool sil164_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
/* Silicon Image 164 driver for chip on i2c bus */
static bool sil164_init(struct intel_dvo_device *dvo,
- struct intel_i2c_chan *i2cbus)
+ struct i2c_adapter *adapter)
{
/* this will detect the SIL164 chip on the specified i2c bus */
struct sil164_priv *sil;
@@ -148,8 +150,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
if (sil == NULL)
return false;
- dvo->i2c_bus = i2cbus;
- dvo->i2c_bus->slave_addr = dvo->slave_addr;
+ dvo->i2c_bus = adapter;
dvo->dev_priv = sil;
sil->quiet = true;
@@ -158,7 +159,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
if (ch != (SIL164_VID & 0xff)) {
DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
- ch, i2cbus->adapter.name, i2cbus->slave_addr);
+ ch, adapter->name, dvo->slave_addr);
goto out;
}
@@ -167,7 +168,7 @@ static bool sil164_init(struct intel_dvo_device *dvo,
if (ch != (SIL164_DID & 0xff)) {
DRM_DEBUG("sil164 not detected got %d: from %s Slave %d.\n",
- ch, i2cbus->adapter.name, i2cbus->slave_addr);
+ ch, adapter->name, dvo->slave_addr);
goto out;
}
sil->quiet = false;
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
index 207fda806eb..9ecc907384e 100644
--- a/drivers/gpu/drm/i915/dvo_tfp410.c
+++ b/drivers/gpu/drm/i915/dvo_tfp410.c
@@ -101,19 +101,20 @@ struct tfp410_priv {
static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
struct tfp410_priv *tfp = dvo->dev_priv;
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
u8 out_buf[2];
u8 in_buf[2];
struct i2c_msg msgs[] = {
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 1,
.buf = out_buf,
},
{
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = I2C_M_RD,
.len = 1,
.buf = in_buf,
@@ -130,7 +131,7 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
if (!tfp->quiet) {
DRM_DEBUG("Unable to read register 0x%02x from %s:%02x.\n",
- addr, i2cbus->adapter.name, i2cbus->slave_addr);
+ addr, i2cbus->adapter.name, dvo->slave_addr);
}
return false;
}
@@ -138,10 +139,11 @@ static bool tfp410_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
{
struct tfp410_priv *tfp = dvo->dev_priv;
- struct intel_i2c_chan *i2cbus = dvo->i2c_bus;
+ struct i2c_adapter *adapter = dvo->i2c_bus;
+ struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
uint8_t out_buf[2];
struct i2c_msg msg = {
- .addr = i2cbus->slave_addr,
+ .addr = dvo->slave_addr,
.flags = 0,
.len = 2,
.buf = out_buf,
@@ -155,7 +157,7 @@ static bool tfp410_writeb(struct intel_dvo_device *dvo, int addr, uint8_t ch)
if (!tfp->quiet) {
DRM_DEBUG("Unable to write register 0x%02x to %s:%d.\n",
- addr, i2cbus->adapter.name, i2cbus->slave_addr);
+ addr, i2cbus->adapter.name, dvo->slave_addr);
}
return false;
@@ -174,7 +176,7 @@ static int tfp410_getid(struct intel_dvo_device *dvo, int addr)
/* Ti TFP410 driver for chip on i2c bus */
static bool tfp410_init(struct intel_dvo_device *dvo,
- struct intel_i2c_chan *i2cbus)
+ struct i2c_adapter *adapter)
{
/* this will detect the tfp410 chip on the specified i2c bus */
struct tfp410_priv *tfp;
@@ -184,20 +186,19 @@ static bool tfp410_init(struct intel_dvo_device *dvo,
if (tfp == NULL)
return false;
- dvo->i2c_bus = i2cbus;
- dvo->i2c_bus->slave_addr = dvo->slave_addr;
+ dvo->i2c_bus = adapter;
dvo->dev_priv = tfp;
tfp->quiet = true;
if ((id = tfp410_getid(dvo, TFP410_VID_LO)) != TFP410_VID) {
DRM_DEBUG("tfp410 not detected got VID %X: from %s Slave %d.\n",
- id, i2cbus->adapter.name, i2cbus->slave_addr);
+ id, adapter->name, dvo->slave_addr);
goto out;
}
if ((id = tfp410_getid(dvo, TFP410_DID_LO)) != TFP410_DID) {
DRM_DEBUG("tfp410 not detected got DID %X: from %s Slave %d.\n",
- id, i2cbus->adapter.name, i2cbus->slave_addr);
+ id, adapter->name, dvo->slave_addr);
goto out;
}
tfp->quiet = false;
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 98560e1e899..e3cb4025e32 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -67,8 +67,6 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
pci_save_state(dev->pdev);
- i915_save_state(dev);
-
/* If KMS is active, we do the leavevt stuff here */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
if (i915_gem_idle(dev))
@@ -77,6 +75,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
drm_irq_uninstall(dev);
}
+ i915_save_state(dev);
+
intel_opregion_free(dev, 1);
if (state.event == PM_EVENT_SUSPEND) {
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7a84f04e843..bb4c2d387b6 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -306,6 +306,17 @@ typedef struct drm_i915_private {
u32 saveCURBPOS;
u32 saveCURBBASE;
u32 saveCURSIZE;
+ u32 saveDP_B;
+ u32 saveDP_C;
+ u32 saveDP_D;
+ u32 savePIPEA_GMCH_DATA_M;
+ u32 savePIPEB_GMCH_DATA_M;
+ u32 savePIPEA_GMCH_DATA_N;
+ u32 savePIPEB_GMCH_DATA_N;
+ u32 savePIPEA_DP_LINK_M;
+ u32 savePIPEB_DP_LINK_M;
+ u32 savePIPEA_DP_LINK_N;
+ u32 savePIPEB_DP_LINK_N;
struct {
struct drm_mm gtt_space;
@@ -857,6 +868,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
IS_I915GM(dev)))
#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev))
+#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index fd2b8bdffe3..876b65cb762 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1006,7 +1006,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
mutex_lock(&dev->struct_mutex);
#if WATCH_BUF
- DRM_INFO("set_domain_ioctl %p(%d), %08x %08x\n",
+ DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
obj, obj->size, read_domains, write_domain);
#endif
if (read_domains & I915_GEM_DOMAIN_GTT) {
@@ -1050,7 +1050,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
}
#if WATCH_BUF
- DRM_INFO("%s: sw_finish %d (%p %d)\n",
+ DRM_INFO("%s: sw_finish %d (%p %zd)\n",
__func__, args->handle, obj, obj->size);
#endif
obj_priv = obj->driver_private;
@@ -2423,7 +2423,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
}
#if WATCH_BUF
- DRM_INFO("Binding object of size %d at 0x%08x\n",
+ DRM_INFO("Binding object of size %zd at 0x%08x\n",
obj->size, obj_priv->gtt_offset);
#endif
ret = i915_gem_object_get_pages(obj);
@@ -4227,6 +4227,7 @@ i915_gem_lastclose(struct drm_device *dev)
void
i915_gem_load(struct drm_device *dev)
{
+ int i;
drm_i915_private_t *dev_priv = dev->dev_private;
spin_lock_init(&dev_priv->mm.active_list_lock);
@@ -4246,6 +4247,18 @@ i915_gem_load(struct drm_device *dev)
else
dev_priv->num_fence_regs = 8;
+ /* Initialize fence registers to zero */
+ if (IS_I965G(dev)) {
+ for (i = 0; i < 16; i++)
+ I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
+ } else {
+ for (i = 0; i < 8; i++)
+ I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+ if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ for (i = 0; i < 8; i++)
+ I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+ }
+
i915_gem_detect_bit_6_swizzle(dev);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
index 8d0b943e2c5..e602614bd3f 100644
--- a/drivers/gpu/drm/i915/i915_gem_debug.c
+++ b/drivers/gpu/drm/i915/i915_gem_debug.c
@@ -87,7 +87,7 @@ i915_gem_dump_object(struct drm_gem_object *obj, int len,
chunk_len = page_len - chunk;
if (chunk_len > 128)
chunk_len = 128;
- i915_gem_dump_page(obj_priv->page_list[page],
+ i915_gem_dump_page(obj_priv->pages[page],
chunk, chunk + chunk_len,
obj_priv->gtt_offset +
page * PAGE_SIZE,
@@ -143,7 +143,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
uint32_t *backing_map = NULL;
int bad_count = 0;
- DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %dkb):\n",
+ DRM_INFO("%s: checking coherency of object %p@0x%08x (%d, %zdkb):\n",
__func__, obj, obj_priv->gtt_offset, handle,
obj->size / 1024);
@@ -157,7 +157,7 @@ i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
for (page = 0; page < obj->size / PAGE_SIZE; page++) {
int i;
- backing_map = kmap_atomic(obj_priv->page_list[page], KM_USER0);
+ backing_map = kmap_atomic(obj_priv->pages[page], KM_USER0);
if (backing_map == NULL) {
DRM_ERROR("failed to map backing page\n");
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 5c1ceec49f5..daeae62e1c2 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -114,11 +114,13 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
/* If ACPI doesn't have it, assume we need to allocate it ourselves */
+#ifdef CONFIG_PNP
if (mchbar_addr &&
pnp_range_reserved(mchbar_addr, mchbar_addr + MCHBAR_SIZE)) {
ret = 0;
goto out_put;
}
+#endif
/* Get some space for it */
ret = pci_bus_alloc_resource(bridge_dev->bus, &dev_priv->mch_res,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b86b7b7130c..228546f6eaa 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -232,7 +232,17 @@ static void i915_hotplug_work_func(struct work_struct *work)
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
hotplug_work);
struct drm_device *dev = dev_priv->dev;
-
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector *connector;
+
+ if (mode_config->num_connector) {
+ list_for_each_entry(connector, &mode_config->connector_list, head) {
+ struct intel_output *intel_output = to_intel_output(connector);
+
+ if (intel_output->hot_plug)
+ (*intel_output->hot_plug) (intel_output);
+ }
+ }
/* Just fire off a uevent and let userspace tell us what to do */
drm_sysfs_hotplug_event(dev);
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f6237a0b113..88bf7521405 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -569,6 +569,19 @@
#define C0DRB3 0x10206
#define C1DRB3 0x10606
+/* Clocking configuration register */
+#define CLKCFG 0x10c00
+#define CLKCFG_FSB_400 (0 << 0) /* hrawclk 100 */
+#define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */
+#define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */
+#define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */
+#define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */
+#define CLKCFG_FSB_1333 (7 << 0) /* hrawclk 333 */
+/* this is a guess, could be 5 as well */
+#define CLKCFG_FSB_1600 (4 << 0) /* hrawclk 400 */
+#define CLKCFG_FSB_1600_ALT (5 << 0) /* hrawclk 400 */
+#define CLKCFG_FSB_MASK (7 << 0)
+
/** GM965 GM45 render standby register */
#define MCHBAR_RENDER_STANDBY 0x111B8
@@ -834,9 +847,25 @@
#define HORIZ_INTERP_MASK (3 << 6)
#define HORIZ_AUTO_SCALE (1 << 5)
#define PANEL_8TO6_DITHER_ENABLE (1 << 3)
+#define PFIT_FILTER_FUZZY (0 << 24)
+#define PFIT_SCALING_AUTO (0 << 26)
+#define PFIT_SCALING_PROGRAMMED (1 << 26)
+#define PFIT_SCALING_PILLAR (2 << 26)
+#define PFIT_SCALING_LETTER (3 << 26)
#define PFIT_PGM_RATIOS 0x61234
#define PFIT_VERT_SCALE_MASK 0xfff00000
#define PFIT_HORIZ_SCALE_MASK 0x0000fff0
+/* Pre-965 */
+#define PFIT_VERT_SCALE_SHIFT 20
+#define PFIT_VERT_SCALE_MASK 0xfff00000
+#define PFIT_HORIZ_SCALE_SHIFT 4
+#define PFIT_HORIZ_SCALE_MASK 0x0000fff0
+/* 965+ */
+#define PFIT_VERT_SCALE_SHIFT_965 16
+#define PFIT_VERT_SCALE_MASK_965 0x1fff0000
+#define PFIT_HORIZ_SCALE_SHIFT_965 0
+#define PFIT_HORIZ_SCALE_MASK_965 0x00001fff
+
#define PFIT_AUTO_RATIOS 0x61238
/* Backlight control */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index a98e2831ed3..8d8e083d14a 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -322,6 +322,20 @@ int i915_save_state(struct drm_device *dev)
dev_priv->savePP_OFF_DELAYS = I915_READ(PP_OFF_DELAYS);
dev_priv->savePP_DIVISOR = I915_READ(PP_DIVISOR);
+ /* Display Port state */
+ if (SUPPORTS_INTEGRATED_DP(dev)) {
+ dev_priv->saveDP_B = I915_READ(DP_B);
+ dev_priv->saveDP_C = I915_READ(DP_C);
+ dev_priv->saveDP_D = I915_READ(DP_D);
+ dev_priv->savePIPEA_GMCH_DATA_M = I915_READ(PIPEA_GMCH_DATA_M);
+ dev_priv->savePIPEB_GMCH_DATA_M = I915_READ(PIPEB_GMCH_DATA_M);
+ dev_priv->savePIPEA_GMCH_DATA_N = I915_READ(PIPEA_GMCH_DATA_N);
+ dev_priv->savePIPEB_GMCH_DATA_N = I915_READ(PIPEB_GMCH_DATA_N);
+ dev_priv->savePIPEA_DP_LINK_M = I915_READ(PIPEA_DP_LINK_M);
+ dev_priv->savePIPEB_DP_LINK_M = I915_READ(PIPEB_DP_LINK_M);
+ dev_priv->savePIPEA_DP_LINK_N = I915_READ(PIPEA_DP_LINK_N);
+ dev_priv->savePIPEB_DP_LINK_N = I915_READ(PIPEB_DP_LINK_N);
+ }
/* FIXME: save TV & SDVO state */
/* FBC state */
@@ -404,7 +418,19 @@ int i915_restore_state(struct drm_device *dev)
for (i = 0; i < 8; i++)
I915_WRITE(FENCE_REG_945_8 + (i * 4), dev_priv->saveFENCE[i+8]);
}
-
+
+ /* Display port ratios (must be done before clock is set) */
+ if (SUPPORTS_INTEGRATED_DP(dev)) {
+ I915_WRITE(PIPEA_GMCH_DATA_M, dev_priv->savePIPEA_GMCH_DATA_M);
+ I915_WRITE(PIPEB_GMCH_DATA_M, dev_priv->savePIPEB_GMCH_DATA_M);
+ I915_WRITE(PIPEA_GMCH_DATA_N, dev_priv->savePIPEA_GMCH_DATA_N);
+ I915_WRITE(PIPEB_GMCH_DATA_N, dev_priv->savePIPEB_GMCH_DATA_N);
+ I915_WRITE(PIPEA_DP_LINK_M, dev_priv->savePIPEA_DP_LINK_M);
+ I915_WRITE(PIPEB_DP_LINK_M, dev_priv->savePIPEB_DP_LINK_M);
+ I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N);
+ I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N);
+ }
+
/* Pipe & plane A info */
/* Prime the clock */
if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
@@ -518,6 +544,12 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE(PP_DIVISOR, dev_priv->savePP_DIVISOR);
I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+ /* Display Port state */
+ if (SUPPORTS_INTEGRATED_DP(dev)) {
+ I915_WRITE(DP_B, dev_priv->saveDP_B);
+ I915_WRITE(DP_C, dev_priv->saveDP_C);
+ I915_WRITE(DP_D, dev_priv->saveDP_D);
+ }
/* FIXME: restore TV & SDVO state */
/* FBC info */
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index cdd126d068a..716409a5724 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -99,9 +99,11 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
{
struct bdb_lvds_options *lvds_options;
struct bdb_lvds_lfp_data *lvds_lfp_data;
+ struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
struct bdb_lvds_lfp_data_entry *entry;
struct lvds_dvo_timing *dvo_timing;
struct drm_display_mode *panel_fixed_mode;
+ int lfp_data_size;
/* Defaults if we can't find VBT info */
dev_priv->lvds_dither = 0;
@@ -119,9 +121,17 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
if (!lvds_lfp_data)
return;
+ lvds_lfp_data_ptrs = find_section(bdb, BDB_LVDS_LFP_DATA_PTRS);
+ if (!lvds_lfp_data_ptrs)
+ return;
+
dev_priv->lvds_vbt = 1;
- entry = &lvds_lfp_data->data[lvds_options->panel_type];
+ lfp_data_size = lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset -
+ lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset;
+ entry = (struct bdb_lvds_lfp_data_entry *)
+ ((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
+ lvds_options->panel_type));
dvo_timing = &entry->dvo_timing;
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 3e1c7816211..73e7b9cecac 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -29,6 +29,7 @@
#include "intel_drv.h"
#include "i915_drm.h"
#include "i915_drv.h"
+#include "intel_dp.h"
#include "drm_crtc_helper.h"
@@ -127,19 +128,6 @@ struct intel_limit {
#define I9XX_P2_LVDS_FAST 7
#define I9XX_P2_LVDS_SLOW_LIMIT 112000
-#define INTEL_LIMIT_I8XX_DVO_DAC 0
-#define INTEL_LIMIT_I8XX_LVDS 1
-#define INTEL_LIMIT_I9XX_SDVO_DAC 2
-#define INTEL_LIMIT_I9XX_LVDS 3
-#define INTEL_LIMIT_G4X_SDVO 4
-#define INTEL_LIMIT_G4X_HDMI_DAC 5
-#define INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS 6
-#define INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS 7
-#define INTEL_LIMIT_IGD_SDVO_DAC 8
-#define INTEL_LIMIT_IGD_LVDS 9
-#define INTEL_LIMIT_IGDNG_SDVO_DAC 10
-#define INTEL_LIMIT_IGDNG_LVDS 11
-
/*The parameter is for SDVO on G4x platform*/
#define G4X_DOT_SDVO_MIN 25000
#define G4X_DOT_SDVO_MAX 270000
@@ -218,6 +206,25 @@ struct intel_limit {
#define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7
#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0
+/*The parameter is for DISPLAY PORT on G4x platform*/
+#define G4X_DOT_DISPLAY_PORT_MIN 161670
+#define G4X_DOT_DISPLAY_PORT_MAX 227000
+#define G4X_N_DISPLAY_PORT_MIN 1
+#define G4X_N_DISPLAY_PORT_MAX 2
+#define G4X_M_DISPLAY_PORT_MIN 97
+#define G4X_M_DISPLAY_PORT_MAX 108
+#define G4X_M1_DISPLAY_PORT_MIN 0x10
+#define G4X_M1_DISPLAY_PORT_MAX 0x12
+#define G4X_M2_DISPLAY_PORT_MIN 0x05
+#define G4X_M2_DISPLAY_PORT_MAX 0x06
+#define G4X_P_DISPLAY_PORT_MIN 10
+#define G4X_P_DISPLAY_PORT_MAX 20
+#define G4X_P1_DISPLAY_PORT_MIN 1
+#define G4X_P1_DISPLAY_PORT_MAX 2
+#define G4X_P2_DISPLAY_PORT_SLOW 10
+#define G4X_P2_DISPLAY_PORT_FAST 10
+#define G4X_P2_DISPLAY_PORT_LIMIT 0
+
/* IGDNG */
/* as we calculate clock using (register_value + 2) for
N/M1/M2, so here the range value for them is (actual_value-2).
@@ -256,8 +263,11 @@ static bool
intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
-static const intel_limit_t intel_limits[] = {
- { /* INTEL_LIMIT_I8XX_DVO_DAC */
+static bool
+intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *best_clock);
+
+static const intel_limit_t intel_limits_i8xx_dvo = {
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
.vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX },
.n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX },
@@ -269,8 +279,9 @@ static const intel_limit_t intel_limits[] = {
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST },
.find_pll = intel_find_best_PLL,
- },
- { /* INTEL_LIMIT_I8XX_LVDS */
+};
+
+static const intel_limit_t intel_limits_i8xx_lvds = {
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
.vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX },
.n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX },
@@ -282,8 +293,9 @@ static const intel_limit_t intel_limits[] = {
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
- },
- { /* INTEL_LIMIT_I9XX_SDVO_DAC */
+};
+
+static const intel_limit_t intel_limits_i9xx_sdvo = {
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
.vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX },
.n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX },
@@ -295,8 +307,9 @@ static const intel_limit_t intel_limits[] = {
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
- },
- { /* INTEL_LIMIT_I9XX_LVDS */
+};
+
+static const intel_limit_t intel_limits_i9xx_lvds = {
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
.vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX },
.n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX },
@@ -311,9 +324,10 @@ static const intel_limit_t intel_limits[] = {
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
- },
+};
+
/* below parameter and function is for G4X Chipset Family*/
- { /* INTEL_LIMIT_G4X_SDVO */
+static const intel_limit_t intel_limits_g4x_sdvo = {
.dot = { .min = G4X_DOT_SDVO_MIN, .max = G4X_DOT_SDVO_MAX },
.vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX},
.n = { .min = G4X_N_SDVO_MIN, .max = G4X_N_SDVO_MAX },
@@ -327,8 +341,9 @@ static const intel_limit_t intel_limits[] = {
.p2_fast = G4X_P2_SDVO_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- },
- { /* INTEL_LIMIT_G4X_HDMI_DAC */
+};
+
+static const intel_limit_t intel_limits_g4x_hdmi = {
.dot = { .min = G4X_DOT_HDMI_DAC_MIN, .max = G4X_DOT_HDMI_DAC_MAX },
.vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX},
.n = { .min = G4X_N_HDMI_DAC_MIN, .max = G4X_N_HDMI_DAC_MAX },
@@ -342,8 +357,9 @@ static const intel_limit_t intel_limits[] = {
.p2_fast = G4X_P2_HDMI_DAC_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- },
- { /* INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS */
+};
+
+static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
.dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN,
.max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX },
.vco = { .min = G4X_VCO_MIN,
@@ -365,8 +381,9 @@ static const intel_limit_t intel_limits[] = {
.p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- },
- { /* INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS */
+};
+
+static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
.dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN,
.max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX },
.vco = { .min = G4X_VCO_MIN,
@@ -388,8 +405,32 @@ static const intel_limit_t intel_limits[] = {
.p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
- },
- { /* INTEL_LIMIT_IGD_SDVO */
+};
+
+static const intel_limit_t intel_limits_g4x_display_port = {
+ .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN,
+ .max = G4X_DOT_DISPLAY_PORT_MAX },
+ .vco = { .min = G4X_VCO_MIN,
+ .max = G4X_VCO_MAX},
+ .n = { .min = G4X_N_DISPLAY_PORT_MIN,
+ .max = G4X_N_DISPLAY_PORT_MAX },
+ .m = { .min = G4X_M_DISPLAY_PORT_MIN,
+ .max = G4X_M_DISPLAY_PORT_MAX },
+ .m1 = { .min = G4X_M1_DISPLAY_PORT_MIN,
+ .max = G4X_M1_DISPLAY_PORT_MAX },
+ .m2 = { .min = G4X_M2_DISPLAY_PORT_MIN,
+ .max = G4X_M2_DISPLAY_PORT_MAX },
+ .p = { .min = G4X_P_DISPLAY_PORT_MIN,
+ .max = G4X_P_DISPLAY_PORT_MAX },
+ .p1 = { .min = G4X_P1_DISPLAY_PORT_MIN,
+ .max = G4X_P1_DISPLAY_PORT_MAX},
+ .p2 = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT,
+ .p2_slow = G4X_P2_DISPLAY_PORT_SLOW,
+ .p2_fast = G4X_P2_DISPLAY_PORT_FAST },
+ .find_pll = intel_find_pll_g4x_dp,
+};
+
+static const intel_limit_t intel_limits_igd_sdvo = {
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
.vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX },
.n = { .min = IGD_N_MIN, .max = IGD_N_MAX },
@@ -401,8 +442,9 @@ static const intel_limit_t intel_limits[] = {
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
- },
- { /* INTEL_LIMIT_IGD_LVDS */
+};
+
+static const intel_limit_t intel_limits_igd_lvds = {
.dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
.vco = { .min = IGD_VCO_MIN, .max = IGD_VCO_MAX },
.n = { .min = IGD_N_MIN, .max = IGD_N_MAX },
@@ -415,8 +457,9 @@ static const intel_limit_t intel_limits[] = {
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
.find_pll = intel_find_best_PLL,
- },
- { /* INTEL_LIMIT_IGDNG_SDVO_DAC */
+};
+
+static const intel_limit_t intel_limits_igdng_sdvo = {
.dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX },
.vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX },
.n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX },
@@ -429,8 +472,9 @@ static const intel_limit_t intel_limits[] = {
.p2_slow = IGDNG_P2_SDVO_DAC_SLOW,
.p2_fast = IGDNG_P2_SDVO_DAC_FAST },
.find_pll = intel_igdng_find_best_PLL,
- },
- { /* INTEL_LIMIT_IGDNG_LVDS */
+};
+
+static const intel_limit_t intel_limits_igdng_lvds = {
.dot = { .min = IGDNG_DOT_MIN, .max = IGDNG_DOT_MAX },
.vco = { .min = IGDNG_VCO_MIN, .max = IGDNG_VCO_MAX },
.n = { .min = IGDNG_N_MIN, .max = IGDNG_N_MAX },
@@ -443,16 +487,15 @@ static const intel_limit_t intel_limits[] = {
.p2_slow = IGDNG_P2_LVDS_SLOW,
.p2_fast = IGDNG_P2_LVDS_FAST },
.find_pll = intel_igdng_find_best_PLL,
- },
};
static const intel_limit_t *intel_igdng_limit(struct drm_crtc *crtc)
{
const intel_limit_t *limit;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
- limit = &intel_limits[INTEL_LIMIT_IGDNG_LVDS];
+ limit = &intel_limits_igdng_lvds;
else
- limit = &intel_limits[INTEL_LIMIT_IGDNG_SDVO_DAC];
+ limit = &intel_limits_igdng_sdvo;
return limit;
}
@@ -467,19 +510,19 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
LVDS_CLKB_POWER_UP)
/* LVDS with dual channel */
- limit = &intel_limits
- [INTEL_LIMIT_G4X_DUAL_CHANNEL_LVDS];
+ limit = &intel_limits_g4x_dual_channel_lvds;
else
/* LVDS with dual channel */
- limit = &intel_limits
- [INTEL_LIMIT_G4X_SINGLE_CHANNEL_LVDS];
+ limit = &intel_limits_g4x_single_channel_lvds;
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI) ||
intel_pipe_has_type(crtc, INTEL_OUTPUT_ANALOG)) {
- limit = &intel_limits[INTEL_LIMIT_G4X_HDMI_DAC];
+ limit = &intel_limits_g4x_hdmi;
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
- limit = &intel_limits[INTEL_LIMIT_G4X_SDVO];
+ limit = &intel_limits_g4x_sdvo;
+ } else if (intel_pipe_has_type (crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+ limit = &intel_limits_g4x_display_port;
} else /* The option is for other outputs */
- limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+ limit = &intel_limits_i9xx_sdvo;
return limit;
}
@@ -495,19 +538,19 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
limit = intel_g4x_limit(crtc);
} else if (IS_I9XX(dev) && !IS_IGD(dev)) {
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
- limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS];
+ limit = &intel_limits_i9xx_lvds;
else
- limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+ limit = &intel_limits_i9xx_sdvo;
} else if (IS_IGD(dev)) {
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
- limit = &intel_limits[INTEL_LIMIT_IGD_LVDS];
+ limit = &intel_limits_igd_lvds;
else
- limit = &intel_limits[INTEL_LIMIT_IGD_SDVO_DAC];
+ limit = &intel_limits_igd_sdvo;
} else {
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
- limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS];
+ limit = &intel_limits_i8xx_lvds;
else
- limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC];
+ limit = &intel_limits_i8xx_dvo;
}
return limit;
}
@@ -764,6 +807,35 @@ out:
return found;
}
+/* DisplayPort has only two frequencies, 162MHz and 270MHz */
+static bool
+intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *best_clock)
+{
+ intel_clock_t clock;
+ if (target < 200000) {
+ clock.dot = 161670;
+ clock.p = 20;
+ clock.p1 = 2;
+ clock.p2 = 10;
+ clock.n = 0x01;
+ clock.m = 97;
+ clock.m1 = 0x10;
+ clock.m2 = 0x05;
+ } else {
+ clock.dot = 270000;
+ clock.p = 10;
+ clock.p1 = 1;
+ clock.p2 = 10;
+ clock.n = 0x02;
+ clock.m = 108;
+ clock.m1 = 0x12;
+ clock.m2 = 0x06;
+ }
+ memcpy(best_clock, &clock, sizeof(intel_clock_t));
+ return true;
+}
+
void
intel_wait_for_vblank(struct drm_device *dev)
{
@@ -1541,7 +1613,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
intel_clock_t clock;
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
bool ok, is_sdvo = false, is_dvo = false;
- bool is_crt = false, is_lvds = false, is_tv = false;
+ bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
const intel_limit_t *limit;
@@ -1585,6 +1657,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_ANALOG:
is_crt = true;
break;
+ case INTEL_OUTPUT_DISPLAYPORT:
+ is_dp = true;
+ break;
}
num_outputs++;
@@ -1600,6 +1675,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
} else {
refclk = 48000;
}
+
/*
* Returns a set of divisors for the desired target clock with the given
@@ -1662,6 +1738,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
else if (IS_IGDNG(dev))
dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
}
+ if (is_dp)
+ dpll |= DPLL_DVO_HIGH_SPEED;
/* compute bitmask from p1 value */
if (IS_IGD(dev))
@@ -1809,6 +1887,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(lvds_reg, lvds);
I915_READ(lvds_reg);
}
+ if (is_dp)
+ intel_dp_set_m_n(crtc, mode, adjusted_mode);
I915_WRITE(fp_reg, fp);
I915_WRITE(dpll_reg, dpll);
@@ -2475,6 +2555,8 @@ static void intel_setup_outputs(struct drm_device *dev)
found = intel_sdvo_init(dev, SDVOB);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
intel_hdmi_init(dev, SDVOB);
+ if (!found && SUPPORTS_INTEGRATED_DP(dev))
+ intel_dp_init(dev, DP_B);
}
/* Before G4X SDVOC doesn't have its own detect register */
@@ -2487,7 +2569,11 @@ static void intel_setup_outputs(struct drm_device *dev)
found = intel_sdvo_init(dev, SDVOC);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
intel_hdmi_init(dev, SDVOC);
+ if (!found && SUPPORTS_INTEGRATED_DP(dev))
+ intel_dp_init(dev, DP_C);
}
+ if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
+ intel_dp_init(dev, DP_D);
} else
intel_dvo_init(dev);
@@ -2530,6 +2616,11 @@ static void intel_setup_outputs(struct drm_device *dev)
(1 << 1));
clone_mask = (1 << INTEL_OUTPUT_TVOUT);
break;
+ case INTEL_OUTPUT_DISPLAYPORT:
+ crtc_mask = ((1 << 0) |
+ (1 << 1));
+ clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
+ break;
}
encoder->possible_crtcs = crtc_mask;
encoder->possible_clones = intel_connector_clones(dev, clone_mask);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
new file mode 100644
index 00000000000..8f8d37d5663
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -0,0 +1,1153 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Packard <keithp@keithp.com>
+ *
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_dp.h"
+
+#define DP_LINK_STATUS_SIZE 6
+#define DP_LINK_CHECK_TIMEOUT (10 * 1000)
+
+#define DP_LINK_CONFIGURATION_SIZE 9
+
+struct intel_dp_priv {
+ uint32_t output_reg;
+ uint32_t DP;
+ uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE];
+ uint32_t save_DP;
+ uint8_t save_link_configuration[DP_LINK_CONFIGURATION_SIZE];
+ bool has_audio;
+ int dpms_mode;
+ uint8_t link_bw;
+ uint8_t lane_count;
+ uint8_t dpcd[4];
+ struct intel_output *intel_output;
+ struct i2c_adapter adapter;
+ struct i2c_algo_dp_aux_data algo;
+};
+
+static void
+intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
+ uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE]);
+
+static void
+intel_dp_link_down(struct intel_output *intel_output, uint32_t DP);
+
+static int
+intel_dp_max_lane_count(struct intel_output *intel_output)
+{
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ int max_lane_count = 4;
+
+ if (dp_priv->dpcd[0] >= 0x11) {
+ max_lane_count = dp_priv->dpcd[2] & 0x1f;
+ switch (max_lane_count) {
+ case 1: case 2: case 4:
+ break;
+ default:
+ max_lane_count = 4;
+ }
+ }
+ return max_lane_count;
+}
+
+static int
+intel_dp_max_link_bw(struct intel_output *intel_output)
+{
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ int max_link_bw = dp_priv->dpcd[1];
+
+ switch (max_link_bw) {
+ case DP_LINK_BW_1_62:
+ case DP_LINK_BW_2_7:
+ break;
+ default:
+ max_link_bw = DP_LINK_BW_1_62;
+ break;
+ }
+ return max_link_bw;
+}
+
+static int
+intel_dp_link_clock(uint8_t link_bw)
+{
+ if (link_bw == DP_LINK_BW_2_7)
+ return 270000;
+ else
+ return 162000;
+}
+
+/* I think this is a fiction */
+static int
+intel_dp_link_required(int pixel_clock)
+{
+ return pixel_clock * 3;
+}
+
+static int
+intel_dp_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct intel_output *intel_output = to_intel_output(connector);
+ int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output));
+ int max_lanes = intel_dp_max_lane_count(intel_output);
+
+ if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes)
+ return MODE_CLOCK_HIGH;
+
+ if (mode->clock < 10000)
+ return MODE_CLOCK_LOW;
+
+ return MODE_OK;
+}
+
+static uint32_t
+pack_aux(uint8_t *src, int src_bytes)
+{
+ int i;
+ uint32_t v = 0;
+
+ if (src_bytes > 4)
+ src_bytes = 4;
+ for (i = 0; i < src_bytes; i++)
+ v |= ((uint32_t) src[i]) << ((3-i) * 8);
+ return v;
+}
+
+static void
+unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
+{
+ int i;
+ if (dst_bytes > 4)
+ dst_bytes = 4;
+ for (i = 0; i < dst_bytes; i++)
+ dst[i] = src >> ((3-i) * 8);
+}
+
+/* hrawclock is 1/4 the FSB frequency */
+static int
+intel_hrawclk(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t clkcfg;
+
+ clkcfg = I915_READ(CLKCFG);
+ switch (clkcfg & CLKCFG_FSB_MASK) {
+ case CLKCFG_FSB_400:
+ return 100;
+ case CLKCFG_FSB_533:
+ return 133;
+ case CLKCFG_FSB_667:
+ return 166;
+ case CLKCFG_FSB_800:
+ return 200;
+ case CLKCFG_FSB_1067:
+ return 266;
+ case CLKCFG_FSB_1333:
+ return 333;
+ /* these two are just a guess; one of them might be right */
+ case CLKCFG_FSB_1600:
+ case CLKCFG_FSB_1600_ALT:
+ return 400;
+ default:
+ return 133;
+ }
+}
+
+static int
+intel_dp_aux_ch(struct intel_output *intel_output,
+ uint8_t *send, int send_bytes,
+ uint8_t *recv, int recv_size)
+{
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ uint32_t output_reg = dp_priv->output_reg;
+ struct drm_device *dev = intel_output->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t ch_ctl = output_reg + 0x10;
+ uint32_t ch_data = ch_ctl + 4;
+ int i;
+ int recv_bytes;
+ uint32_t ctl;
+ uint32_t status;
+ uint32_t aux_clock_divider;
+ int try;
+
+ /* The clock divider is based off the hrawclk,
+ * and would like to run at 2MHz. So, take the
+ * hrawclk value and divide by 2 and use that
+ */
+ aux_clock_divider = intel_hrawclk(dev) / 2;
+ /* Must try at least 3 times according to DP spec */
+ for (try = 0; try < 5; try++) {
+ /* Load the send data into the aux channel data registers */
+ for (i = 0; i < send_bytes; i += 4) {
+ uint32_t d = pack_aux(send + i, send_bytes - i);;
+
+ I915_WRITE(ch_data + i, d);
+ }
+
+ ctl = (DP_AUX_CH_CTL_SEND_BUSY |
+ DP_AUX_CH_CTL_TIME_OUT_400us |
+ (send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
+ (5 << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
+ (aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
+ DP_AUX_CH_CTL_DONE |
+ DP_AUX_CH_CTL_TIME_OUT_ERROR |
+ DP_AUX_CH_CTL_RECEIVE_ERROR);
+
+ /* Send the command and wait for it to complete */
+ I915_WRITE(ch_ctl, ctl);
+ (void) I915_READ(ch_ctl);
+ for (;;) {
+ udelay(100);
+ status = I915_READ(ch_ctl);
+ if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
+ break;
+ }
+
+ /* Clear done status and any errors */
+ I915_WRITE(ch_ctl, (ctl |
+ DP_AUX_CH_CTL_DONE |
+ DP_AUX_CH_CTL_TIME_OUT_ERROR |
+ DP_AUX_CH_CTL_RECEIVE_ERROR));
+ (void) I915_READ(ch_ctl);
+ if ((status & DP_AUX_CH_CTL_TIME_OUT_ERROR) == 0)
+ break;
+ }
+
+ if ((status & DP_AUX_CH_CTL_DONE) == 0) {
+ printk(KERN_ERR "dp_aux_ch not done status 0x%08x\n", status);
+ return -EBUSY;
+ }
+
+ /* Check for timeout or receive error.
+ * Timeouts occur when the sink is not connected
+ */
+ if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
+ printk(KERN_ERR "dp_aux_ch receive error status 0x%08x\n", status);
+ return -EIO;
+ }
+ if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
+ printk(KERN_ERR "dp_aux_ch timeout status 0x%08x\n", status);
+ return -ETIMEDOUT;
+ }
+
+ /* Unload any bytes sent back from the other side */
+ recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
+ DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+
+ if (recv_bytes > recv_size)
+ recv_bytes = recv_size;
+
+ for (i = 0; i < recv_bytes; i += 4) {
+ uint32_t d = I915_READ(ch_data + i);
+
+ unpack_aux(d, recv + i, recv_bytes - i);
+ }
+
+ return recv_bytes;
+}
+
+/* Write data to the aux channel in native mode */
+static int
+intel_dp_aux_native_write(struct intel_output *intel_output,
+ uint16_t address, uint8_t *send, int send_bytes)
+{
+ int ret;
+ uint8_t msg[20];
+ int msg_bytes;
+ uint8_t ack;
+
+ if (send_bytes > 16)
+ return -1;
+ msg[0] = AUX_NATIVE_WRITE << 4;
+ msg[1] = address >> 8;
+ msg[2] = address;
+ msg[3] = send_bytes - 1;
+ memcpy(&msg[4], send, send_bytes);
+ msg_bytes = send_bytes + 4;
+ for (;;) {
+ ret = intel_dp_aux_ch(intel_output, msg, msg_bytes, &ack, 1);
+ if (ret < 0)
+ return ret;
+ if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+ break;
+ else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+ udelay(100);
+ else
+ return -EIO;
+ }
+ return send_bytes;
+}
+
+/* Write a single byte to the aux channel in native mode */
+static int
+intel_dp_aux_native_write_1(struct intel_output *intel_output,
+ uint16_t address, uint8_t byte)
+{
+ return intel_dp_aux_native_write(intel_output, address, &byte, 1);
+}
+
+/* read bytes from a native aux channel */
+static int
+intel_dp_aux_native_read(struct intel_output *intel_output,
+ uint16_t address, uint8_t *recv, int recv_bytes)
+{
+ uint8_t msg[4];
+ int msg_bytes;
+ uint8_t reply[20];
+ int reply_bytes;
+ uint8_t ack;
+ int ret;
+
+ msg[0] = AUX_NATIVE_READ << 4;
+ msg[1] = address >> 8;
+ msg[2] = address & 0xff;
+ msg[3] = recv_bytes - 1;
+
+ msg_bytes = 4;
+ reply_bytes = recv_bytes + 1;
+
+ for (;;) {
+ ret = intel_dp_aux_ch(intel_output, msg, msg_bytes,
+ reply, reply_bytes);
+ if (ret == 0)
+ return -EPROTO;
+ if (ret < 0)
+ return ret;
+ ack = reply[0];
+ if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
+ memcpy(recv, reply + 1, ret - 1);
+ return ret - 1;
+ }
+ else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+ udelay(100);
+ else
+ return -EIO;
+ }
+}
+
+static int
+intel_dp_i2c_aux_ch(struct i2c_adapter *adapter,
+ uint8_t *send, int send_bytes,
+ uint8_t *recv, int recv_bytes)
+{
+ struct intel_dp_priv *dp_priv = container_of(adapter,
+ struct intel_dp_priv,
+ adapter);
+ struct intel_output *intel_output = dp_priv->intel_output;
+
+ return intel_dp_aux_ch(intel_output,
+ send, send_bytes, recv, recv_bytes);
+}
+
+static int
+intel_dp_i2c_init(struct intel_output *intel_output, const char *name)
+{
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+ DRM_ERROR("i2c_init %s\n", name);
+ dp_priv->algo.running = false;
+ dp_priv->algo.address = 0;
+ dp_priv->algo.aux_ch = intel_dp_i2c_aux_ch;
+
+ memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter));
+ dp_priv->adapter.owner = THIS_MODULE;
+ dp_priv->adapter.class = I2C_CLASS_DDC;
+ strncpy (dp_priv->adapter.name, name, sizeof dp_priv->adapter.name - 1);
+ dp_priv->adapter.name[sizeof dp_priv->adapter.name - 1] = '\0';
+ dp_priv->adapter.algo_data = &dp_priv->algo;
+ dp_priv->adapter.dev.parent = &intel_output->base.kdev;
+
+ return i2c_dp_aux_add_bus(&dp_priv->adapter);
+}
+
+static bool
+intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct intel_output *intel_output = enc_to_intel_output(encoder);
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ int lane_count, clock;
+ int max_lane_count = intel_dp_max_lane_count(intel_output);
+ int max_clock = intel_dp_max_link_bw(intel_output) == DP_LINK_BW_2_7 ? 1 : 0;
+ static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
+
+ for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+ for (clock = 0; clock <= max_clock; clock++) {
+ int link_avail = intel_dp_link_clock(bws[clock]) * lane_count;
+
+ if (intel_dp_link_required(mode->clock) <= link_avail) {
+ dp_priv->link_bw = bws[clock];
+ dp_priv->lane_count = lane_count;
+ adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
+ printk(KERN_ERR "link bw %02x lane count %d clock %d\n",
+ dp_priv->link_bw, dp_priv->lane_count,
+ adjusted_mode->clock);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+struct intel_dp_m_n {
+ uint32_t tu;
+ uint32_t gmch_m;
+ uint32_t gmch_n;
+ uint32_t link_m;
+ uint32_t link_n;
+};
+
+static void
+intel_reduce_ratio(uint32_t *num, uint32_t *den)
+{
+ while (*num > 0xffffff || *den > 0xffffff) {
+ *num >>= 1;
+ *den >>= 1;
+ }
+}
+
+static void
+intel_dp_compute_m_n(int bytes_per_pixel,
+ int nlanes,
+ int pixel_clock,
+ int link_clock,
+ struct intel_dp_m_n *m_n)
+{
+ m_n->tu = 64;
+ m_n->gmch_m = pixel_clock * bytes_per_pixel;
+ m_n->gmch_n = link_clock * nlanes;
+ intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
+ m_n->link_m = pixel_clock;
+ m_n->link_n = link_clock;
+ intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
+}
+
+void
+intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector *connector;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int lane_count = 4;
+ struct intel_dp_m_n m_n;
+
+ /*
+ * Find the lane count in the intel_output private
+ */
+ list_for_each_entry(connector, &mode_config->connector_list, head) {
+ struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+ if (!connector->encoder || connector->encoder->crtc != crtc)
+ continue;
+
+ if (intel_output->type == INTEL_OUTPUT_DISPLAYPORT) {
+ lane_count = dp_priv->lane_count;
+ break;
+ }
+ }
+
+ /*
+ * Compute the GMCH and Link ratios. The '3' here is
+ * the number of bytes_per_pixel post-LUT, which we always
+ * set up for 8-bits of R/G/B, or 3 bytes total.
+ */
+ intel_dp_compute_m_n(3, lane_count,
+ mode->clock, adjusted_mode->clock, &m_n);
+
+ if (intel_crtc->pipe == 0) {
+ I915_WRITE(PIPEA_GMCH_DATA_M,
+ ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+ m_n.gmch_m);
+ I915_WRITE(PIPEA_GMCH_DATA_N,
+ m_n.gmch_n);
+ I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
+ I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
+ } else {
+ I915_WRITE(PIPEB_GMCH_DATA_M,
+ ((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
+ m_n.gmch_m);
+ I915_WRITE(PIPEB_GMCH_DATA_N,
+ m_n.gmch_n);
+ I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
+ I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
+ }
+}
+
+static void
+intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct intel_output *intel_output = enc_to_intel_output(encoder);
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct drm_crtc *crtc = intel_output->enc.crtc;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ dp_priv->DP = (DP_LINK_TRAIN_OFF |
+ DP_VOLTAGE_0_4 |
+ DP_PRE_EMPHASIS_0 |
+ DP_SYNC_VS_HIGH |
+ DP_SYNC_HS_HIGH);
+
+ switch (dp_priv->lane_count) {
+ case 1:
+ dp_priv->DP |= DP_PORT_WIDTH_1;
+ break;
+ case 2:
+ dp_priv->DP |= DP_PORT_WIDTH_2;
+ break;
+ case 4:
+ dp_priv->DP |= DP_PORT_WIDTH_4;
+ break;
+ }
+ if (dp_priv->has_audio)
+ dp_priv->DP |= DP_AUDIO_OUTPUT_ENABLE;
+
+ memset(dp_priv->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
+ dp_priv->link_configuration[0] = dp_priv->link_bw;
+ dp_priv->link_configuration[1] = dp_priv->lane_count;
+
+ /*
+ * Check for DPCD version > 1.1,
+ * enable enahanced frame stuff in that case
+ */
+ if (dp_priv->dpcd[0] >= 0x11) {
+ dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+ dp_priv->DP |= DP_ENHANCED_FRAMING;
+ }
+
+ if (intel_crtc->pipe == 1)
+ dp_priv->DP |= DP_PIPEB_SELECT;
+}
+
+
+static void
+intel_dp_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct intel_output *intel_output = enc_to_intel_output(encoder);
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ struct drm_device *dev = intel_output->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dp_reg = I915_READ(dp_priv->output_reg);
+
+ if (mode != DRM_MODE_DPMS_ON) {
+ if (dp_reg & DP_PORT_EN)
+ intel_dp_link_down(intel_output, dp_priv->DP);
+ } else {
+ if (!(dp_reg & DP_PORT_EN))
+ intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
+ }
+ dp_priv->dpms_mode = mode;
+}
+
+/*
+ * Fetch AUX CH registers 0x202 - 0x207 which contain
+ * link status information
+ */
+static bool
+intel_dp_get_link_status(struct intel_output *intel_output,
+ uint8_t link_status[DP_LINK_STATUS_SIZE])
+{
+ int ret;
+
+ ret = intel_dp_aux_native_read(intel_output,
+ DP_LANE0_1_STATUS,
+ link_status, DP_LINK_STATUS_SIZE);
+ if (ret != DP_LINK_STATUS_SIZE)
+ return false;
+ return true;
+}
+
+static uint8_t
+intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
+ int r)
+{
+ return link_status[r - DP_LANE0_1_STATUS];
+}
+
+static void
+intel_dp_save(struct drm_connector *connector)
+{
+ struct intel_output *intel_output = to_intel_output(connector);
+ struct drm_device *dev = intel_output->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+ dp_priv->save_DP = I915_READ(dp_priv->output_reg);
+ intel_dp_aux_native_read(intel_output, DP_LINK_BW_SET,
+ dp_priv->save_link_configuration,
+ sizeof (dp_priv->save_link_configuration));
+}
+
+static uint8_t
+intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
+ int lane)
+{
+ int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+ int s = ((lane & 1) ?
+ DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
+ DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
+ uint8_t l = intel_dp_link_status(link_status, i);
+
+ return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
+}
+
+static uint8_t
+intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
+ int lane)
+{
+ int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+ int s = ((lane & 1) ?
+ DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
+ DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
+ uint8_t l = intel_dp_link_status(link_status, i);
+
+ return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
+}
+
+
+#if 0
+static char *voltage_names[] = {
+ "0.4V", "0.6V", "0.8V", "1.2V"
+};
+static char *pre_emph_names[] = {
+ "0dB", "3.5dB", "6dB", "9.5dB"
+};
+static char *link_train_names[] = {
+ "pattern 1", "pattern 2", "idle", "off"
+};
+#endif
+
+/*
+ * These are source-specific values; current Intel hardware supports
+ * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
+ */
+#define I830_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_800
+
+static uint8_t
+intel_dp_pre_emphasis_max(uint8_t voltage_swing)
+{
+ switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ case DP_TRAIN_VOLTAGE_SWING_400:
+ return DP_TRAIN_PRE_EMPHASIS_6;
+ case DP_TRAIN_VOLTAGE_SWING_600:
+ return DP_TRAIN_PRE_EMPHASIS_6;
+ case DP_TRAIN_VOLTAGE_SWING_800:
+ return DP_TRAIN_PRE_EMPHASIS_3_5;
+ case DP_TRAIN_VOLTAGE_SWING_1200:
+ default:
+ return DP_TRAIN_PRE_EMPHASIS_0;
+ }
+}
+
+static void
+intel_get_adjust_train(struct intel_output *intel_output,
+ uint8_t link_status[DP_LINK_STATUS_SIZE],
+ int lane_count,
+ uint8_t train_set[4])
+{
+ uint8_t v = 0;
+ uint8_t p = 0;
+ int lane;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane);
+ uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane);
+
+ if (this_v > v)
+ v = this_v;
+ if (this_p > p)
+ p = this_p;
+ }
+
+ if (v >= I830_DP_VOLTAGE_MAX)
+ v = I830_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+
+ if (p >= intel_dp_pre_emphasis_max(v))
+ p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+
+ for (lane = 0; lane < 4; lane++)
+ train_set[lane] = v | p;
+}
+
+static uint32_t
+intel_dp_signal_levels(uint8_t train_set, int lane_count)
+{
+ uint32_t signal_levels = 0;
+
+ switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ case DP_TRAIN_VOLTAGE_SWING_400:
+ default:
+ signal_levels |= DP_VOLTAGE_0_4;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_600:
+ signal_levels |= DP_VOLTAGE_0_6;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_800:
+ signal_levels |= DP_VOLTAGE_0_8;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_1200:
+ signal_levels |= DP_VOLTAGE_1_2;
+ break;
+ }
+ switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+ case DP_TRAIN_PRE_EMPHASIS_0:
+ default:
+ signal_levels |= DP_PRE_EMPHASIS_0;
+ break;
+ case DP_TRAIN_PRE_EMPHASIS_3_5:
+ signal_levels |= DP_PRE_EMPHASIS_3_5;
+ break;
+ case DP_TRAIN_PRE_EMPHASIS_6:
+ signal_levels |= DP_PRE_EMPHASIS_6;
+ break;
+ case DP_TRAIN_PRE_EMPHASIS_9_5:
+ signal_levels |= DP_PRE_EMPHASIS_9_5;
+ break;
+ }
+ return signal_levels;
+}
+
+static uint8_t
+intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
+ int lane)
+{
+ int i = DP_LANE0_1_STATUS + (lane >> 1);
+ int s = (lane & 1) * 4;
+ uint8_t l = intel_dp_link_status(link_status, i);
+
+ return (l >> s) & 0xf;
+}
+
+/* Check for clock recovery is done on all channels */
+static bool
+intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+{
+ int lane;
+ uint8_t lane_status;
+
+ for (lane = 0; lane < lane_count; lane++) {
+ lane_status = intel_get_lane_status(link_status, lane);
+ if ((lane_status & DP_LANE_CR_DONE) == 0)
+ return false;
+ }
+ return true;
+}
+
+/* Check to see if channel eq is done on all channels */
+#define CHANNEL_EQ_BITS (DP_LANE_CR_DONE|\
+ DP_LANE_CHANNEL_EQ_DONE|\
+ DP_LANE_SYMBOL_LOCKED)
+static bool
+intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+{
+ uint8_t lane_align;
+ uint8_t lane_status;
+ int lane;
+
+ lane_align = intel_dp_link_status(link_status,
+ DP_LANE_ALIGN_STATUS_UPDATED);
+ if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
+ return false;
+ for (lane = 0; lane < lane_count; lane++) {
+ lane_status = intel_get_lane_status(link_status, lane);
+ if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
+ return false;
+ }
+ return true;
+}
+
+static bool
+intel_dp_set_link_train(struct intel_output *intel_output,
+ uint32_t dp_reg_value,
+ uint8_t dp_train_pat,
+ uint8_t train_set[4],
+ bool first)
+{
+ struct drm_device *dev = intel_output->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ int ret;
+
+ I915_WRITE(dp_priv->output_reg, dp_reg_value);
+ POSTING_READ(dp_priv->output_reg);
+ if (first)
+ intel_wait_for_vblank(dev);
+
+ intel_dp_aux_native_write_1(intel_output,
+ DP_TRAINING_PATTERN_SET,
+ dp_train_pat);
+
+ ret = intel_dp_aux_native_write(intel_output,
+ DP_TRAINING_LANE0_SET, train_set, 4);
+ if (ret != 4)
+ return false;
+
+ return true;
+}
+
+static void
+intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
+ uint8_t link_configuration[DP_LINK_CONFIGURATION_SIZE])
+{
+ struct drm_device *dev = intel_output->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ uint8_t train_set[4];
+ uint8_t link_status[DP_LINK_STATUS_SIZE];
+ int i;
+ uint8_t voltage;
+ bool clock_recovery = false;
+ bool channel_eq = false;
+ bool first = true;
+ int tries;
+
+ /* Write the link configuration data */
+ intel_dp_aux_native_write(intel_output, 0x100,
+ link_configuration, DP_LINK_CONFIGURATION_SIZE);
+
+ DP |= DP_PORT_EN;
+ DP &= ~DP_LINK_TRAIN_MASK;
+ memset(train_set, 0, 4);
+ voltage = 0xff;
+ tries = 0;
+ clock_recovery = false;
+ for (;;) {
+ /* Use train_set[0] to set the voltage and pre emphasis values */
+ uint32_t signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
+ DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+
+ if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_1,
+ DP_TRAINING_PATTERN_1, train_set, first))
+ break;
+ first = false;
+ /* Set training pattern 1 */
+
+ udelay(100);
+ if (!intel_dp_get_link_status(intel_output, link_status))
+ break;
+
+ if (intel_clock_recovery_ok(link_status, dp_priv->lane_count)) {
+ clock_recovery = true;
+ break;
+ }
+
+ /* Check to see if we've tried the max voltage */
+ for (i = 0; i < dp_priv->lane_count; i++)
+ if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+ break;
+ if (i == dp_priv->lane_count)
+ break;
+
+ /* Check to see if we've tried the same voltage 5 times */
+ if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+ ++tries;
+ if (tries == 5)
+ break;
+ } else
+ tries = 0;
+ voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+
+ /* Compute new train_set as requested by target */
+ intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set);
+ }
+
+ /* channel equalization */
+ tries = 0;
+ channel_eq = false;
+ for (;;) {
+ /* Use train_set[0] to set the voltage and pre emphasis values */
+ uint32_t signal_levels = intel_dp_signal_levels(train_set[0], dp_priv->lane_count);
+ DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
+
+ /* channel eq pattern */
+ if (!intel_dp_set_link_train(intel_output, DP | DP_LINK_TRAIN_PAT_2,
+ DP_TRAINING_PATTERN_2, train_set,
+ false))
+ break;
+
+ udelay(400);
+ if (!intel_dp_get_link_status(intel_output, link_status))
+ break;
+
+ if (intel_channel_eq_ok(link_status, dp_priv->lane_count)) {
+ channel_eq = true;
+ break;
+ }
+
+ /* Try 5 times */
+ if (tries > 5)
+ break;
+
+ /* Compute new train_set as requested by target */
+ intel_get_adjust_train(intel_output, link_status, dp_priv->lane_count, train_set);
+ ++tries;
+ }
+
+ I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_OFF);
+ POSTING_READ(dp_priv->output_reg);
+ intel_dp_aux_native_write_1(intel_output,
+ DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
+}
+
+static void
+intel_dp_link_down(struct intel_output *intel_output, uint32_t DP)
+{
+ struct drm_device *dev = intel_output->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+ I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN);
+ POSTING_READ(dp_priv->output_reg);
+}
+
+static void
+intel_dp_restore(struct drm_connector *connector)
+{
+ struct intel_output *intel_output = to_intel_output(connector);
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+ if (dp_priv->save_DP & DP_PORT_EN)
+ intel_dp_link_train(intel_output, dp_priv->save_DP, dp_priv->save_link_configuration);
+ else
+ intel_dp_link_down(intel_output, dp_priv->save_DP);
+}
+
+/*
+ * According to DP spec
+ * 5.1.2:
+ * 1. Read DPCD
+ * 2. Configure link according to Receiver Capabilities
+ * 3. Use Link Training from 2.5.3.3 and 3.5.1.3
+ * 4. Check link status on receipt of hot-plug interrupt
+ */
+
+static void
+intel_dp_check_link_status(struct intel_output *intel_output)
+{
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+ if (!intel_output->enc.crtc)
+ return;
+
+ if (!intel_dp_get_link_status(intel_output, link_status)) {
+ intel_dp_link_down(intel_output, dp_priv->DP);
+ return;
+ }
+
+ if (!intel_channel_eq_ok(link_status, dp_priv->lane_count))
+ intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
+}
+
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
+ *
+ * \return true if DP port is connected.
+ * \return false if DP port is disconnected.
+ */
+static enum drm_connector_status
+intel_dp_detect(struct drm_connector *connector)
+{
+ struct intel_output *intel_output = to_intel_output(connector);
+ struct drm_device *dev = intel_output->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+ uint32_t temp, bit;
+ enum drm_connector_status status;
+
+ dp_priv->has_audio = false;
+
+ temp = I915_READ(PORT_HOTPLUG_EN);
+
+ I915_WRITE(PORT_HOTPLUG_EN,
+ temp |
+ DPB_HOTPLUG_INT_EN |
+ DPC_HOTPLUG_INT_EN |
+ DPD_HOTPLUG_INT_EN);
+
+ POSTING_READ(PORT_HOTPLUG_EN);
+
+ switch (dp_priv->output_reg) {
+ case DP_B:
+ bit = DPB_HOTPLUG_INT_STATUS;
+ break;
+ case DP_C:
+ bit = DPC_HOTPLUG_INT_STATUS;
+ break;
+ case DP_D:
+ bit = DPD_HOTPLUG_INT_STATUS;
+ break;
+ default:
+ return connector_status_unknown;
+ }
+
+ temp = I915_READ(PORT_HOTPLUG_STAT);
+
+ if ((temp & bit) == 0)
+ return connector_status_disconnected;
+
+ status = connector_status_disconnected;
+ if (intel_dp_aux_native_read(intel_output,
+ 0x000, dp_priv->dpcd,
+ sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
+ {
+ if (dp_priv->dpcd[0] != 0)
+ status = connector_status_connected;
+ }
+ return status;
+}
+
+static int intel_dp_get_modes(struct drm_connector *connector)
+{
+ struct intel_output *intel_output = to_intel_output(connector);
+
+ /* We should parse the EDID data and find out if it has an audio sink
+ */
+
+ return intel_ddc_get_modes(intel_output);
+}
+
+static void
+intel_dp_destroy (struct drm_connector *connector)
+{
+ struct intel_output *intel_output = to_intel_output(connector);
+
+ if (intel_output->i2c_bus)
+ intel_i2c_destroy(intel_output->i2c_bus);
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+ kfree(intel_output);
+}
+
+static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
+ .dpms = intel_dp_dpms,
+ .mode_fixup = intel_dp_mode_fixup,
+ .prepare = intel_encoder_prepare,
+ .mode_set = intel_dp_mode_set,
+ .commit = intel_encoder_commit,
+};
+
+static const struct drm_connector_funcs intel_dp_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .save = intel_dp_save,
+ .restore = intel_dp_restore,
+ .detect = intel_dp_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = intel_dp_destroy,
+};
+
+static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
+ .get_modes = intel_dp_get_modes,
+ .mode_valid = intel_dp_mode_valid,
+ .best_encoder = intel_best_encoder,
+};
+
+static void intel_dp_enc_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs intel_dp_enc_funcs = {
+ .destroy = intel_dp_enc_destroy,
+};
+
+void
+intel_dp_hot_plug(struct intel_output *intel_output)
+{
+ struct intel_dp_priv *dp_priv = intel_output->dev_priv;
+
+ if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON)
+ intel_dp_check_link_status(intel_output);
+}
+
+void
+intel_dp_init(struct drm_device *dev, int output_reg)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_connector *connector;
+ struct intel_output *intel_output;
+ struct intel_dp_priv *dp_priv;
+
+ intel_output = kcalloc(sizeof(struct intel_output) +
+ sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
+ if (!intel_output)
+ return;
+
+ dp_priv = (struct intel_dp_priv *)(intel_output + 1);
+
+ connector = &intel_output->base;
+ drm_connector_init(dev, connector, &intel_dp_connector_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort);
+ drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
+
+ intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
+
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = 0;
+
+ dp_priv->intel_output = intel_output;
+ dp_priv->output_reg = output_reg;
+ dp_priv->has_audio = false;
+ dp_priv->dpms_mode = DRM_MODE_DPMS_ON;
+ intel_output->dev_priv = dp_priv;
+
+ drm_encoder_init(dev, &intel_output->enc, &intel_dp_enc_funcs,
+ DRM_MODE_ENCODER_TMDS);
+ drm_encoder_helper_add(&intel_output->enc, &intel_dp_helper_funcs);
+
+ drm_mode_connector_attach_encoder(&intel_output->base,
+ &intel_output->enc);
+ drm_sysfs_connector_add(connector);
+
+ /* Set up the DDC bus. */
+ intel_dp_i2c_init(intel_output,
+ (output_reg == DP_B) ? "DPDDC-B" :
+ (output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D");
+ intel_output->ddc_bus = &dp_priv->adapter;
+ intel_output->hot_plug = intel_dp_hot_plug;
+
+ /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
+ * 0xd. Failure to do so will result in spurious interrupts being
+ * generated on the port when a cable is not attached.
+ */
+ if (IS_G4X(dev) && !IS_GM45(dev)) {
+ u32 temp = I915_READ(PEG_BAND_GAP_DATA);
+ I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
+ }
+}
diff --git a/drivers/gpu/drm/i915/intel_dp.h b/drivers/gpu/drm/i915/intel_dp.h
new file mode 100644
index 00000000000..2b38054d3b6
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dp.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2008 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _INTEL_DP_H_
+#define _INTEL_DP_H_
+
+/* From the VESA DisplayPort spec */
+
+#define AUX_NATIVE_WRITE 0x8
+#define AUX_NATIVE_READ 0x9
+#define AUX_I2C_WRITE 0x0
+#define AUX_I2C_READ 0x1
+#define AUX_I2C_STATUS 0x2
+#define AUX_I2C_MOT 0x4
+
+#define AUX_NATIVE_REPLY_ACK (0x0 << 4)
+#define AUX_NATIVE_REPLY_NACK (0x1 << 4)
+#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
+#define AUX_NATIVE_REPLY_MASK (0x3 << 4)
+
+#define AUX_I2C_REPLY_ACK (0x0 << 6)
+#define AUX_I2C_REPLY_NACK (0x1 << 6)
+#define AUX_I2C_REPLY_DEFER (0x2 << 6)
+#define AUX_I2C_REPLY_MASK (0x3 << 6)
+
+/* AUX CH addresses */
+#define DP_LINK_BW_SET 0x100
+# define DP_LINK_BW_1_62 0x06
+# define DP_LINK_BW_2_7 0x0a
+
+#define DP_LANE_COUNT_SET 0x101
+# define DP_LANE_COUNT_MASK 0x0f
+# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7)
+
+#define DP_TRAINING_PATTERN_SET 0x102
+
+# define DP_TRAINING_PATTERN_DISABLE 0
+# define DP_TRAINING_PATTERN_1 1
+# define DP_TRAINING_PATTERN_2 2
+# define DP_TRAINING_PATTERN_MASK 0x3
+
+# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2)
+# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2)
+# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2)
+# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2)
+# define DP_LINK_QUAL_PATTERN_MASK (3 << 2)
+
+# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4)
+# define DP_LINK_SCRAMBLING_DISABLE (1 << 5)
+
+# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6)
+# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6)
+# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6)
+# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6)
+
+#define DP_TRAINING_LANE0_SET 0x103
+#define DP_TRAINING_LANE1_SET 0x104
+#define DP_TRAINING_LANE2_SET 0x105
+#define DP_TRAINING_LANE3_SET 0x106
+
+# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3
+# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0
+# define DP_TRAIN_MAX_SWING_REACHED (1 << 2)
+# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0)
+# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0)
+
+# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3)
+# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3)
+
+# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3
+# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5)
+
+#define DP_DOWNSPREAD_CTRL 0x107
+# define DP_SPREAD_AMP_0_5 (1 << 4)
+
+#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108
+# define DP_SET_ANSI_8B10B (1 << 0)
+
+#define DP_LANE0_1_STATUS 0x202
+#define DP_LANE2_3_STATUS 0x203
+
+# define DP_LANE_CR_DONE (1 << 0)
+# define DP_LANE_CHANNEL_EQ_DONE (1 << 1)
+# define DP_LANE_SYMBOL_LOCKED (1 << 2)
+
+#define DP_LANE_ALIGN_STATUS_UPDATED 0x204
+
+#define DP_INTERLANE_ALIGN_DONE (1 << 0)
+#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6)
+#define DP_LINK_STATUS_UPDATED (1 << 7)
+
+#define DP_SINK_STATUS 0x205
+
+#define DP_RECEIVE_PORT_0_STATUS (1 << 0)
+#define DP_RECEIVE_PORT_1_STATUS (1 << 1)
+
+#define DP_ADJUST_REQUEST_LANE0_1 0x206
+#define DP_ADJUST_REQUEST_LANE2_3 0x207
+
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6
+
+struct i2c_algo_dp_aux_data {
+ bool running;
+ u16 address;
+ int (*aux_ch) (struct i2c_adapter *adapter,
+ uint8_t *send, int send_bytes,
+ uint8_t *recv, int recv_bytes);
+};
+
+int
+i2c_dp_aux_add_bus(struct i2c_adapter *adapter);
+
+#endif /* _INTEL_DP_H_ */
diff --git a/drivers/gpu/drm/i915/intel_dp_i2c.c b/drivers/gpu/drm/i915/intel_dp_i2c.c
new file mode 100644
index 00000000000..4e60f14b1a6
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_dp_i2c.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright © 2009 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include "intel_dp.h"
+
+/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
+
+#define MODE_I2C_START 1
+#define MODE_I2C_WRITE 2
+#define MODE_I2C_READ 4
+#define MODE_I2C_STOP 8
+
+static int
+i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
+ uint8_t write_byte, uint8_t *read_byte)
+{
+ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ uint16_t address = algo_data->address;
+ uint8_t msg[5];
+ uint8_t reply[2];
+ int msg_bytes;
+ int reply_bytes;
+ int ret;
+
+ /* Set up the command byte */
+ if (mode & MODE_I2C_READ)
+ msg[0] = AUX_I2C_READ << 4;
+ else
+ msg[0] = AUX_I2C_WRITE << 4;
+
+ if (!(mode & MODE_I2C_STOP))
+ msg[0] |= AUX_I2C_MOT << 4;
+
+ msg[1] = address >> 8;
+ msg[2] = address;
+
+ switch (mode) {
+ case MODE_I2C_WRITE:
+ msg[3] = 0;
+ msg[4] = write_byte;
+ msg_bytes = 5;
+ reply_bytes = 1;
+ break;
+ case MODE_I2C_READ:
+ msg[3] = 0;
+ msg_bytes = 4;
+ reply_bytes = 2;
+ break;
+ default:
+ msg_bytes = 3;
+ reply_bytes = 1;
+ break;
+ }
+
+ for (;;) {
+ ret = (*algo_data->aux_ch)(adapter,
+ msg, msg_bytes,
+ reply, reply_bytes);
+ if (ret < 0) {
+ printk(KERN_ERR "aux_ch failed %d\n", ret);
+ return ret;
+ }
+ switch (reply[0] & AUX_I2C_REPLY_MASK) {
+ case AUX_I2C_REPLY_ACK:
+ if (mode == MODE_I2C_READ) {
+ *read_byte = reply[1];
+ }
+ return reply_bytes - 1;
+ case AUX_I2C_REPLY_NACK:
+ printk(KERN_ERR "aux_ch nack\n");
+ return -EREMOTEIO;
+ case AUX_I2C_REPLY_DEFER:
+ printk(KERN_ERR "aux_ch defer\n");
+ udelay(100);
+ break;
+ default:
+ printk(KERN_ERR "aux_ch invalid reply 0x%02x\n", reply[0]);
+ return -EREMOTEIO;
+ }
+ }
+}
+
+/*
+ * I2C over AUX CH
+ */
+
+/*
+ * Send the address. If the I2C link is running, this 'restarts'
+ * the connection with the new address, this is used for doing
+ * a write followed by a read (as needed for DDC)
+ */
+static int
+i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
+{
+ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ int mode = MODE_I2C_START;
+ int ret;
+
+ if (reading)
+ mode |= MODE_I2C_READ;
+ else
+ mode |= MODE_I2C_WRITE;
+ algo_data->address = address;
+ algo_data->running = true;
+ ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
+ return ret;
+}
+
+/*
+ * Stop the I2C transaction. This closes out the link, sending
+ * a bare address packet with the MOT bit turned off
+ */
+static void
+i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
+{
+ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ int mode = MODE_I2C_STOP;
+
+ if (reading)
+ mode |= MODE_I2C_READ;
+ else
+ mode |= MODE_I2C_WRITE;
+ if (algo_data->running) {
+ (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
+ algo_data->running = false;
+ }
+}
+
+/*
+ * Write a single byte to the current I2C address, the
+ * the I2C link must be running or this returns -EIO
+ */
+static int
+i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
+{
+ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ int ret;
+
+ if (!algo_data->running)
+ return -EIO;
+
+ ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
+ return ret;
+}
+
+/*
+ * Read a single byte from the current I2C address, the
+ * I2C link must be running or this returns -EIO
+ */
+static int
+i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
+{
+ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ int ret;
+
+ if (!algo_data->running)
+ return -EIO;
+
+ ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
+ return ret;
+}
+
+static int
+i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs,
+ int num)
+{
+ int ret = 0;
+ bool reading = false;
+ int m;
+ int b;
+
+ for (m = 0; m < num; m++) {
+ u16 len = msgs[m].len;
+ u8 *buf = msgs[m].buf;
+ reading = (msgs[m].flags & I2C_M_RD) != 0;
+ ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
+ if (ret < 0)
+ break;
+ if (reading) {
+ for (b = 0; b < len; b++) {
+ ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]);
+ if (ret < 0)
+ break;
+ }
+ } else {
+ for (b = 0; b < len; b++) {
+ ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]);
+ if (ret < 0)
+ break;
+ }
+ }
+ if (ret < 0)
+ break;
+ }
+ if (ret >= 0)
+ ret = num;
+ i2c_algo_dp_aux_stop(adapter, reading);
+ printk(KERN_ERR "dp_aux_xfer return %d\n", ret);
+ return ret;
+}
+
+static u32
+i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm i2c_dp_aux_algo = {
+ .master_xfer = i2c_algo_dp_aux_xfer,
+ .functionality = i2c_algo_dp_aux_functionality,
+};
+
+static void
+i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
+{
+ (void) i2c_algo_dp_aux_address(adapter, 0, false);
+ (void) i2c_algo_dp_aux_stop(adapter, false);
+
+}
+
+static int
+i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
+{
+ adapter->algo = &i2c_dp_aux_algo;
+ adapter->retries = 3;
+ i2c_dp_aux_reset_bus(adapter);
+ return 0;
+}
+
+int
+i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
+{
+ int error;
+
+ error = i2c_dp_aux_prepare_bus(adapter);
+ if (error)
+ return error;
+ error = i2c_add_adapter(adapter);
+ return error;
+}
+EXPORT_SYMBOL(i2c_dp_aux_add_bus);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cd4b9c5f715..004541c935a 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -54,6 +54,7 @@
#define INTEL_OUTPUT_LVDS 4
#define INTEL_OUTPUT_TVOUT 5
#define INTEL_OUTPUT_HDMI 6
+#define INTEL_OUTPUT_DISPLAYPORT 7
#define INTEL_DVO_CHIP_NONE 0
#define INTEL_DVO_CHIP_LVDS 1
@@ -65,7 +66,6 @@ struct intel_i2c_chan {
u32 reg; /* GPIO reg */
struct i2c_adapter adapter;
struct i2c_algo_bit_data algo;
- u8 slave_addr;
};
struct intel_framebuffer {
@@ -79,11 +79,12 @@ struct intel_output {
struct drm_encoder enc;
int type;
- struct intel_i2c_chan *i2c_bus; /* for control functions */
- struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */
+ struct i2c_adapter *i2c_bus;
+ struct i2c_adapter *ddc_bus;
bool load_detect_temp;
bool needs_tv_clock;
void *dev_priv;
+ void (*hot_plug)(struct intel_output *);
};
struct intel_crtc {
@@ -104,9 +105,9 @@ struct intel_crtc {
#define enc_to_intel_output(x) container_of(x, struct intel_output, enc)
#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
-struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
- const char *name);
-void intel_i2c_destroy(struct intel_i2c_chan *chan);
+struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
+ const char *name);
+void intel_i2c_destroy(struct i2c_adapter *adapter);
int intel_ddc_get_modes(struct intel_output *intel_output);
extern bool intel_ddc_probe(struct intel_output *intel_output);
void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
@@ -116,6 +117,10 @@ extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
extern void intel_dvo_init(struct drm_device *dev);
extern void intel_tv_init(struct drm_device *dev);
extern void intel_lvds_init(struct drm_device *dev);
+extern void intel_dp_init(struct drm_device *dev, int dp_reg);
+void
+intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_encoder_prepare (struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 1ee3007d6ec..13bff20930e 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -384,10 +384,9 @@ void intel_dvo_init(struct drm_device *dev)
{
struct intel_output *intel_output;
struct intel_dvo_device *dvo;
- struct intel_i2c_chan *i2cbus = NULL;
+ struct i2c_adapter *i2cbus = NULL;
int ret = 0;
int i;
- int gpio_inited = 0;
int encoder_type = DRM_MODE_ENCODER_NONE;
intel_output = kzalloc (sizeof(struct intel_output), GFP_KERNEL);
if (!intel_output)
@@ -420,14 +419,11 @@ void intel_dvo_init(struct drm_device *dev)
* It appears that everything is on GPIOE except for panels
* on i830 laptops, which are on GPIOB (DVOA).
*/
- if (gpio_inited != gpio) {
- if (i2cbus != NULL)
- intel_i2c_destroy(i2cbus);
- if (!(i2cbus = intel_i2c_create(dev, gpio,
- gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
- continue;
- }
- gpio_inited = gpio;
+ if (i2cbus != NULL)
+ intel_i2c_destroy(i2cbus);
+ if (!(i2cbus = intel_i2c_create(dev, gpio,
+ gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
+ continue;
}
if (dvo->dev_ops!= NULL)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 4ea2a651b92..9e30daae37d 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -31,6 +31,7 @@
#include "drmP.h"
#include "drm.h"
#include "drm_crtc.h"
+#include "drm_edid.h"
#include "intel_drv.h"
#include "i915_drm.h"
#include "i915_drv.h"
@@ -56,8 +57,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
sdvox = SDVO_ENCODING_HDMI |
SDVO_BORDER_ENABLE |
SDVO_VSYNC_ACTIVE_HIGH |
- SDVO_HSYNC_ACTIVE_HIGH |
- SDVO_NULL_PACKETS_DURING_VSYNC;
+ SDVO_HSYNC_ACTIVE_HIGH;
if (hdmi_priv->has_hdmi_sink)
sdvox |= SDVO_AUDIO_ENABLE;
@@ -129,20 +129,26 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
return true;
}
-static void
-intel_hdmi_sink_detect(struct drm_connector *connector)
+static enum drm_connector_status
+intel_hdmi_edid_detect(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
struct edid *edid = NULL;
+ enum drm_connector_status status = connector_status_disconnected;
edid = drm_get_edid(&intel_output->base,
- &intel_output->ddc_bus->adapter);
- if (edid != NULL) {
- hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
- kfree(edid);
+ intel_output->ddc_bus);
+ hdmi_priv->has_hdmi_sink = false;
+ if (edid) {
+ if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+ status = connector_status_connected;
+ hdmi_priv->has_hdmi_sink = drm_detect_hdmi_monitor(edid);
+ }
intel_output->base.display_info.raw_edid = NULL;
+ kfree(edid);
}
+ return status;
}
static enum drm_connector_status
@@ -154,11 +160,7 @@ igdng_hdmi_detect(struct drm_connector *connector)
/* FIXME hotplug detect */
hdmi_priv->has_hdmi_sink = false;
- intel_hdmi_sink_detect(connector);
- if (hdmi_priv->has_hdmi_sink)
- return connector_status_connected;
- else
- return connector_status_disconnected;
+ return intel_hdmi_edid_detect(connector);
}
static enum drm_connector_status
@@ -201,10 +203,9 @@ intel_hdmi_detect(struct drm_connector *connector)
return connector_status_unknown;
}
- if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0) {
- intel_hdmi_sink_detect(connector);
- return connector_status_connected;
- } else
+ if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0)
+ return intel_hdmi_edid_detect(connector);
+ else
return connector_status_disconnected;
}
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index f7061f68d05..62b8bead765 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -124,6 +124,7 @@ static void set_data(void *data, int state_high)
* @output: driver specific output device
* @reg: GPIO reg to use
* @name: name for this bus
+ * @slave_addr: slave address (if fixed)
*
* Creates and registers a new i2c bus with the Linux i2c layer, for use
* in output probing and control (e.g. DDC or SDVO control functions).
@@ -139,8 +140,8 @@ static void set_data(void *data, int state_high)
* %GPIOH
* see PRM for details on how these different busses are used.
*/
-struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
- const char *name)
+struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
+ const char *name)
{
struct intel_i2c_chan *chan;
@@ -174,7 +175,7 @@ struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
intel_i2c_quirk_set(dev, false);
udelay(20);
- return chan;
+ return &chan->adapter;
out_free:
kfree(chan);
@@ -187,11 +188,16 @@ out_free:
*
* Unregister the adapter from the i2c layer, then free the structure.
*/
-void intel_i2c_destroy(struct intel_i2c_chan *chan)
+void intel_i2c_destroy(struct i2c_adapter *adapter)
{
- if (!chan)
+ struct intel_i2c_chan *chan;
+
+ if (!adapter)
return;
+ chan = container_of(adapter,
+ struct intel_i2c_chan,
+ adapter);
i2c_del_adapter(&chan->adapter);
kfree(chan);
}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index f073ed8432e..9564ca44a97 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -39,6 +39,21 @@
#define I915_LVDS "i915_lvds"
+/*
+ * the following four scaling options are defined.
+ * #define DRM_MODE_SCALE_NON_GPU 0
+ * #define DRM_MODE_SCALE_FULLSCREEN 1
+ * #define DRM_MODE_SCALE_NO_SCALE 2
+ * #define DRM_MODE_SCALE_ASPECT 3
+ */
+
+/* Private structure for the integrated LVDS support */
+struct intel_lvds_priv {
+ int fitting_mode;
+ u32 pfit_control;
+ u32 pfit_pgm_ratios;
+};
+
/**
* Sets the backlight level.
*
@@ -213,10 +228,27 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ /*
+ * float point operation is not supported . So the PANEL_RATIO_FACTOR
+ * is defined, which can avoid the float point computation when
+ * calculating the panel ratio.
+ */
+#define PANEL_RATIO_FACTOR 8192
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct drm_encoder *tmp_encoder;
+ struct intel_output *intel_output = enc_to_intel_output(encoder);
+ struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+ u32 pfit_control = 0, pfit_pgm_ratios = 0;
+ int left_border = 0, right_border = 0, top_border = 0;
+ int bottom_border = 0;
+ bool border = 0;
+ int panel_ratio, desired_ratio, vert_scale, horiz_scale;
+ int horiz_ratio, vert_ratio;
+ u32 hsync_width, vsync_width;
+ u32 hblank_width, vblank_width;
+ u32 hsync_pos, vsync_pos;
/* Should never happen!! */
if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
@@ -232,7 +264,9 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
return false;
}
}
-
+ /* If we don't have a panel mode, there is nothing we can do */
+ if (dev_priv->panel_fixed_mode == NULL)
+ return true;
/*
* If we have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode,
@@ -256,6 +290,243 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
}
+ /* Make sure pre-965s set dither correctly */
+ if (!IS_I965G(dev)) {
+ if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
+ pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+ }
+
+ /* Native modes don't need fitting */
+ if (adjusted_mode->hdisplay == mode->hdisplay &&
+ adjusted_mode->vdisplay == mode->vdisplay) {
+ pfit_pgm_ratios = 0;
+ border = 0;
+ goto out;
+ }
+
+ /* 965+ wants fuzzy fitting */
+ if (IS_I965G(dev))
+ pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
+ PFIT_FILTER_FUZZY;
+
+ hsync_width = adjusted_mode->crtc_hsync_end -
+ adjusted_mode->crtc_hsync_start;
+ vsync_width = adjusted_mode->crtc_vsync_end -
+ adjusted_mode->crtc_vsync_start;
+ hblank_width = adjusted_mode->crtc_hblank_end -
+ adjusted_mode->crtc_hblank_start;
+ vblank_width = adjusted_mode->crtc_vblank_end -
+ adjusted_mode->crtc_vblank_start;
+ /*
+ * Deal with panel fitting options. Figure out how to stretch the
+ * image based on its aspect ratio & the current panel fitting mode.
+ */
+ panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR /
+ adjusted_mode->vdisplay;
+ desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR /
+ mode->vdisplay;
+ /*
+ * Enable automatic panel scaling for non-native modes so that they fill
+ * the screen. Should be enabled before the pipe is enabled, according
+ * to register description and PRM.
+ * Change the value here to see the borders for debugging
+ */
+ I915_WRITE(BCLRPAT_A, 0);
+ I915_WRITE(BCLRPAT_B, 0);
+
+ switch (lvds_priv->fitting_mode) {
+ case DRM_MODE_SCALE_NO_SCALE:
+ /*
+ * For centered modes, we have to calculate border widths &
+ * heights and modify the values programmed into the CRTC.
+ */
+ left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2;
+ right_border = left_border;
+ if (mode->hdisplay & 1)
+ right_border++;
+ top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2;
+ bottom_border = top_border;
+ if (mode->vdisplay & 1)
+ bottom_border++;
+ /* Set active & border values */
+ adjusted_mode->crtc_hdisplay = mode->hdisplay;
+ /* Keep the boder be even */
+ if (right_border & 1)
+ right_border++;
+ /* use the border directly instead of border minuse one */
+ adjusted_mode->crtc_hblank_start = mode->hdisplay +
+ right_border;
+ /* keep the blank width constant */
+ adjusted_mode->crtc_hblank_end =
+ adjusted_mode->crtc_hblank_start + hblank_width;
+ /* get the hsync pos relative to hblank start */
+ hsync_pos = (hblank_width - hsync_width) / 2;
+ /* keep the hsync pos be even */
+ if (hsync_pos & 1)
+ hsync_pos++;
+ adjusted_mode->crtc_hsync_start =
+ adjusted_mode->crtc_hblank_start + hsync_pos;
+ /* keep the hsync width constant */
+ adjusted_mode->crtc_hsync_end =
+ adjusted_mode->crtc_hsync_start + hsync_width;
+ adjusted_mode->crtc_vdisplay = mode->vdisplay;
+ /* use the border instead of border minus one */
+ adjusted_mode->crtc_vblank_start = mode->vdisplay +
+ bottom_border;
+ /* keep the vblank width constant */
+ adjusted_mode->crtc_vblank_end =
+ adjusted_mode->crtc_vblank_start + vblank_width;
+ /* get the vsync start postion relative to vblank start */
+ vsync_pos = (vblank_width - vsync_width) / 2;
+ adjusted_mode->crtc_vsync_start =
+ adjusted_mode->crtc_vblank_start + vsync_pos;
+ /* keep the vsync width constant */
+ adjusted_mode->crtc_vsync_end =
+ adjusted_mode->crtc_vblank_start + vsync_width;
+ border = 1;
+ break;
+ case DRM_MODE_SCALE_ASPECT:
+ /* Scale but preserve the spect ratio */
+ pfit_control |= PFIT_ENABLE;
+ if (IS_I965G(dev)) {
+ /* 965+ is easy, it does everything in hw */
+ if (panel_ratio > desired_ratio)
+ pfit_control |= PFIT_SCALING_PILLAR;
+ else if (panel_ratio < desired_ratio)
+ pfit_control |= PFIT_SCALING_LETTER;
+ else
+ pfit_control |= PFIT_SCALING_AUTO;
+ } else {
+ /*
+ * For earlier chips we have to calculate the scaling
+ * ratio by hand and program it into the
+ * PFIT_PGM_RATIO register
+ */
+ u32 horiz_bits, vert_bits, bits = 12;
+ horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/
+ adjusted_mode->hdisplay;
+ vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/
+ adjusted_mode->vdisplay;
+ horiz_scale = adjusted_mode->hdisplay *
+ PANEL_RATIO_FACTOR / mode->hdisplay;
+ vert_scale = adjusted_mode->vdisplay *
+ PANEL_RATIO_FACTOR / mode->vdisplay;
+
+ /* retain aspect ratio */
+ if (panel_ratio > desired_ratio) { /* Pillar */
+ u32 scaled_width;
+ scaled_width = mode->hdisplay * vert_scale /
+ PANEL_RATIO_FACTOR;
+ horiz_ratio = vert_ratio;
+ pfit_control |= (VERT_AUTO_SCALE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ /* Pillar will have left/right borders */
+ left_border = (adjusted_mode->hdisplay -
+ scaled_width) / 2;
+ right_border = left_border;
+ if (mode->hdisplay & 1) /* odd resolutions */
+ right_border++;
+ /* keep the border be even */
+ if (right_border & 1)
+ right_border++;
+ adjusted_mode->crtc_hdisplay = scaled_width;
+ /* use border instead of border minus one */
+ adjusted_mode->crtc_hblank_start =
+ scaled_width + right_border;
+ /* keep the hblank width constant */
+ adjusted_mode->crtc_hblank_end =
+ adjusted_mode->crtc_hblank_start +
+ hblank_width;
+ /*
+ * get the hsync start pos relative to
+ * hblank start
+ */
+ hsync_pos = (hblank_width - hsync_width) / 2;
+ /* keep the hsync_pos be even */
+ if (hsync_pos & 1)
+ hsync_pos++;
+ adjusted_mode->crtc_hsync_start =
+ adjusted_mode->crtc_hblank_start +
+ hsync_pos;
+ /* keept hsync width constant */
+ adjusted_mode->crtc_hsync_end =
+ adjusted_mode->crtc_hsync_start +
+ hsync_width;
+ border = 1;
+ } else if (panel_ratio < desired_ratio) { /* letter */
+ u32 scaled_height = mode->vdisplay *
+ horiz_scale / PANEL_RATIO_FACTOR;
+ vert_ratio = horiz_ratio;
+ pfit_control |= (HORIZ_AUTO_SCALE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ /* Letterbox will have top/bottom border */
+ top_border = (adjusted_mode->vdisplay -
+ scaled_height) / 2;
+ bottom_border = top_border;
+ if (mode->vdisplay & 1)
+ bottom_border++;
+ adjusted_mode->crtc_vdisplay = scaled_height;
+ /* use border instead of border minus one */
+ adjusted_mode->crtc_vblank_start =
+ scaled_height + bottom_border;
+ /* keep the vblank width constant */
+ adjusted_mode->crtc_vblank_end =
+ adjusted_mode->crtc_vblank_start +
+ vblank_width;
+ /*
+ * get the vsync start pos relative to
+ * vblank start
+ */
+ vsync_pos = (vblank_width - vsync_width) / 2;
+ adjusted_mode->crtc_vsync_start =
+ adjusted_mode->crtc_vblank_start +
+ vsync_pos;
+ /* keep the vsync width constant */
+ adjusted_mode->crtc_vsync_end =
+ adjusted_mode->crtc_vsync_start +
+ vsync_width;
+ border = 1;
+ } else {
+ /* Aspects match, Let hw scale both directions */
+ pfit_control |= (VERT_AUTO_SCALE |
+ HORIZ_AUTO_SCALE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ }
+ horiz_bits = (1 << bits) * horiz_ratio /
+ PANEL_RATIO_FACTOR;
+ vert_bits = (1 << bits) * vert_ratio /
+ PANEL_RATIO_FACTOR;
+ pfit_pgm_ratios =
+ ((vert_bits << PFIT_VERT_SCALE_SHIFT) &
+ PFIT_VERT_SCALE_MASK) |
+ ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) &
+ PFIT_HORIZ_SCALE_MASK);
+ }
+ break;
+
+ case DRM_MODE_SCALE_FULLSCREEN:
+ /*
+ * Full scaling, even if it changes the aspect ratio.
+ * Fortunately this is all done for us in hw.
+ */
+ pfit_control |= PFIT_ENABLE;
+ if (IS_I965G(dev))
+ pfit_control |= PFIT_SCALING_AUTO;
+ else
+ pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ break;
+ default:
+ break;
+ }
+
+out:
+ lvds_priv->pfit_control = pfit_control;
+ lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios;
/*
* XXX: It would be nice to support lower refresh rates on the
* panels to reduce power consumption, and perhaps match the
@@ -301,8 +572,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- u32 pfit_control;
+ struct intel_output *intel_output = enc_to_intel_output(encoder);
+ struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
/*
* The LVDS pin pair will already have been turned on in the
@@ -319,22 +590,8 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
* screen. Should be enabled before the pipe is enabled, according to
* register description and PRM.
*/
- if (mode->hdisplay != adjusted_mode->hdisplay ||
- mode->vdisplay != adjusted_mode->vdisplay)
- pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
- HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR);
- else
- pfit_control = 0;
-
- if (!IS_I965G(dev)) {
- if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
- pfit_control |= PANEL_8TO6_DITHER_ENABLE;
- }
- else
- pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
-
- I915_WRITE(PFIT_CONTROL, pfit_control);
+ I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios);
+ I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control);
}
/**
@@ -406,6 +663,34 @@ static int intel_lvds_set_property(struct drm_connector *connector,
struct drm_property *property,
uint64_t value)
{
+ struct drm_device *dev = connector->dev;
+ struct intel_output *intel_output =
+ to_intel_output(connector);
+
+ if (property == dev->mode_config.scaling_mode_property &&
+ connector->encoder) {
+ struct drm_crtc *crtc = connector->encoder->crtc;
+ struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
+ if (value == DRM_MODE_SCALE_NON_GPU) {
+ DRM_DEBUG_KMS(I915_LVDS,
+ "non_GPU property is unsupported\n");
+ return 0;
+ }
+ if (lvds_priv->fitting_mode == value) {
+ /* the LVDS scaling property is not changed */
+ return 0;
+ }
+ lvds_priv->fitting_mode = value;
+ if (crtc && crtc->enabled) {
+ /*
+ * If the CRTC is enabled, the display will be changed
+ * according to the new panel fitting mode.
+ */
+ drm_crtc_helper_set_mode(crtc, &crtc->mode,
+ crtc->x, crtc->y, crtc->fb);
+ }
+ }
+
return 0;
}
@@ -456,7 +741,7 @@ static const struct dmi_system_id intel_no_lvds[] = {
.callback = intel_no_lvds_dmi_callback,
.ident = "Apple Mac Mini (Core series)",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
},
},
@@ -464,7 +749,7 @@ static const struct dmi_system_id intel_no_lvds[] = {
.callback = intel_no_lvds_dmi_callback,
.ident = "Apple Mac Mini (Core 2 series)",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
DMI_MATCH(DMI_PRODUCT_NAME, "Macmini2,1"),
},
},
@@ -518,6 +803,7 @@ void intel_lvds_init(struct drm_device *dev)
struct drm_encoder *encoder;
struct drm_display_mode *scan; /* *modes, *bios_mode; */
struct drm_crtc *crtc;
+ struct intel_lvds_priv *lvds_priv;
u32 lvds;
int pipe, gpio = GPIOC;
@@ -531,7 +817,8 @@ void intel_lvds_init(struct drm_device *dev)
gpio = PCH_GPIOC;
}
- intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
+ intel_output = kzalloc(sizeof(struct intel_output) +
+ sizeof(struct intel_lvds_priv), GFP_KERNEL);
if (!intel_output) {
return;
}
@@ -553,7 +840,18 @@ void intel_lvds_init(struct drm_device *dev)
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
+ lvds_priv = (struct intel_lvds_priv *)(intel_output + 1);
+ intel_output->dev_priv = lvds_priv;
+ /* create the scaling mode property */
+ drm_mode_create_scaling_mode_property(dev);
+ /*
+ * the initial panel fitting mode will be FULL_SCREEN.
+ */
+ drm_connector_attach_property(&intel_output->base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_FULLSCREEN);
+ lvds_priv->fitting_mode = DRM_MODE_SCALE_FULLSCREEN;
/*
* LVDS discovery:
* 1) check for EDID on DDC
@@ -649,5 +947,5 @@ failed:
if (intel_output->ddc_bus)
intel_i2c_destroy(intel_output->ddc_bus);
drm_connector_cleanup(connector);
- kfree(connector);
+ kfree(intel_output);
}
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index e0910fefce8..67e2f4632a2 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -53,10 +53,9 @@ bool intel_ddc_probe(struct intel_output *intel_output)
}
};
- intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
- ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2);
- intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
-
+ intel_i2c_quirk_set(intel_output->base.dev, true);
+ ret = i2c_transfer(intel_output->ddc_bus, msgs, 2);
+ intel_i2c_quirk_set(intel_output->base.dev, false);
if (ret == 2)
return true;
@@ -74,10 +73,9 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
struct edid *edid;
int ret = 0;
- intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, true);
- edid = drm_get_edid(&intel_output->base,
- &intel_output->ddc_bus->adapter);
- intel_i2c_quirk_set(intel_output->ddc_bus->drm_dev, false);
+ intel_i2c_quirk_set(intel_output->base.dev, true);
+ edid = drm_get_edid(&intel_output->base, intel_output->ddc_bus);
+ intel_i2c_quirk_set(intel_output->base.dev, false);
if (edid) {
drm_mode_connector_update_edid_property(&intel_output->base,
edid);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 9a00adb3a50..f03473779fe 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -38,8 +38,7 @@
#undef SDVO_DEBUG
#define I915_SDVO "i915_sdvo"
struct intel_sdvo_priv {
- struct intel_i2c_chan *i2c_bus;
- int slaveaddr;
+ u8 slave_addr;
/* Register for the SDVO device: SDVOB or SDVOC */
int output_device;
@@ -146,13 +145,13 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
struct i2c_msg msgs[] = {
{
- .addr = sdvo_priv->i2c_bus->slave_addr,
+ .addr = sdvo_priv->slave_addr >> 1,
.flags = 0,
.len = 1,
.buf = out_buf,
},
{
- .addr = sdvo_priv->i2c_bus->slave_addr,
+ .addr = sdvo_priv->slave_addr >> 1,
.flags = I2C_M_RD,
.len = 1,
.buf = buf,
@@ -162,7 +161,7 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
out_buf[0] = addr;
out_buf[1] = 0;
- if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2)
+ if ((ret = i2c_transfer(intel_output->i2c_bus, msgs, 2)) == 2)
{
*ch = buf[0];
return true;
@@ -175,10 +174,11 @@ static bool intel_sdvo_read_byte(struct intel_output *intel_output, u8 addr,
static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
u8 ch)
{
+ struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
u8 out_buf[2];
struct i2c_msg msgs[] = {
{
- .addr = intel_output->i2c_bus->slave_addr,
+ .addr = sdvo_priv->slave_addr >> 1,
.flags = 0,
.len = 2,
.buf = out_buf,
@@ -188,7 +188,7 @@ static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
out_buf[0] = addr;
out_buf[1] = ch;
- if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1)
+ if (i2c_transfer(intel_output->i2c_bus, msgs, 1) == 1)
{
return true;
}
@@ -1369,9 +1369,8 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
struct edid *edid = NULL;
- intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
edid = drm_get_edid(&intel_output->base,
- &intel_output->ddc_bus->adapter);
+ intel_output->ddc_bus);
if (edid != NULL) {
sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid);
kfree(edid);
@@ -1549,7 +1548,6 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
{
struct intel_output *intel_output = to_intel_output(connector);
- struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
struct drm_i915_private *dev_priv = connector->dev->dev_private;
/*
@@ -1557,8 +1555,6 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
* Assume that the preferred modes are
* arranged in priority order.
*/
- /* set the bus switch and get the modes */
- intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
intel_ddc_get_modes(intel_output);
if (list_empty(&connector->probed_modes) == false)
return;
@@ -1709,7 +1705,7 @@ intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan)
list_for_each_entry(connector,
&dev->mode_config.connector_list, head) {
- if (to_intel_output(connector)->ddc_bus == chan) {
+ if (to_intel_output(connector)->ddc_bus == &chan->adapter) {
intel_output = to_intel_output(connector);
break;
}
@@ -1723,7 +1719,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
struct intel_output *intel_output;
struct intel_sdvo_priv *sdvo_priv;
struct i2c_algo_bit_data *algo_data;
- struct i2c_algorithm *algo;
+ const struct i2c_algorithm *algo;
algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
intel_output =
@@ -1733,7 +1729,7 @@ static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
return -EINVAL;
sdvo_priv = intel_output->dev_priv;
- algo = (struct i2c_algorithm *)intel_output->i2c_bus->adapter.algo;
+ algo = intel_output->i2c_bus->algo;
intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
return algo->master_xfer(i2c_adap, msgs, num);
@@ -1785,13 +1781,11 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
struct drm_connector *connector;
struct intel_output *intel_output;
struct intel_sdvo_priv *sdvo_priv;
- struct intel_i2c_chan *i2cbus = NULL;
- struct intel_i2c_chan *ddcbus = NULL;
+
int connector_type;
u8 ch[0x40];
int i;
- int encoder_type, output_id;
- u8 slave_addr;
+ int encoder_type;
intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
if (!intel_output) {
@@ -1799,29 +1793,24 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
}
sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
+ sdvo_priv->output_device = output_device;
+
+ intel_output->dev_priv = sdvo_priv;
intel_output->type = INTEL_OUTPUT_SDVO;
/* setup the DDC bus. */
if (output_device == SDVOB)
- i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
+ intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
else
- i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+ intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
- if (!i2cbus)
+ if (!intel_output->i2c_bus)
goto err_inteloutput;
- slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
- sdvo_priv->i2c_bus = i2cbus;
+ sdvo_priv->slave_addr = intel_sdvo_get_slave_addr(dev, output_device);
- if (output_device == SDVOB) {
- output_id = 1;
- } else {
- output_id = 2;
- }
- sdvo_priv->i2c_bus->slave_addr = slave_addr >> 1;
- sdvo_priv->output_device = output_device;
- intel_output->i2c_bus = i2cbus;
- intel_output->dev_priv = sdvo_priv;
+ /* Save the bit-banging i2c functionality for use by the DDC wrapper */
+ intel_sdvo_i2c_bit_algo.functionality = intel_output->i2c_bus->algo->functionality;
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
@@ -1835,17 +1824,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
/* setup the DDC bus. */
if (output_device == SDVOB)
- ddcbus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
+ intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
else
- ddcbus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
+ intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
- if (ddcbus == NULL)
+ if (intel_output->ddc_bus == NULL)
goto err_i2c;
- intel_sdvo_i2c_bit_algo.functionality =
- intel_output->i2c_bus->adapter.algo->functionality;
- ddcbus->adapter.algo = &intel_sdvo_i2c_bit_algo;
- intel_output->ddc_bus = ddcbus;
+ /* Wrap with our custom algo which switches to DDC mode */
+ intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
/* In defaut case sdvo lvds is false */
sdvo_priv->is_lvds = false;
@@ -1965,9 +1952,10 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
return true;
err_i2c:
- if (ddcbus != NULL)
+ if (intel_output->ddc_bus != NULL)
intel_i2c_destroy(intel_output->ddc_bus);
- intel_i2c_destroy(intel_output->i2c_bus);
+ if (intel_output->i2c_bus != NULL)
+ intel_i2c_destroy(intel_output->i2c_bus);
err_inteloutput:
kfree(intel_output);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index ea68992e441..a43c98e3f07 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1383,34 +1383,31 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
/*
* Detect TV by polling)
*/
- if (intel_output->load_detect_temp) {
- /* TV not currently running, prod it with destructive detect */
- save_tv_dac = tv_dac;
- tv_ctl = I915_READ(TV_CTL);
- save_tv_ctl = tv_ctl;
- tv_ctl &= ~TV_ENC_ENABLE;
- tv_ctl &= ~TV_TEST_MODE_MASK;
- tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
- tv_dac &= ~TVDAC_SENSE_MASK;
- tv_dac &= ~DAC_A_MASK;
- tv_dac &= ~DAC_B_MASK;
- tv_dac &= ~DAC_C_MASK;
- tv_dac |= (TVDAC_STATE_CHG_EN |
- TVDAC_A_SENSE_CTL |
- TVDAC_B_SENSE_CTL |
- TVDAC_C_SENSE_CTL |
- DAC_CTL_OVERRIDE |
- DAC_A_0_7_V |
- DAC_B_0_7_V |
- DAC_C_0_7_V);
- I915_WRITE(TV_CTL, tv_ctl);
- I915_WRITE(TV_DAC, tv_dac);
- intel_wait_for_vblank(dev);
- tv_dac = I915_READ(TV_DAC);
- I915_WRITE(TV_DAC, save_tv_dac);
- I915_WRITE(TV_CTL, save_tv_ctl);
- intel_wait_for_vblank(dev);
- }
+ save_tv_dac = tv_dac;
+ tv_ctl = I915_READ(TV_CTL);
+ save_tv_ctl = tv_ctl;
+ tv_ctl &= ~TV_ENC_ENABLE;
+ tv_ctl &= ~TV_TEST_MODE_MASK;
+ tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
+ tv_dac &= ~TVDAC_SENSE_MASK;
+ tv_dac &= ~DAC_A_MASK;
+ tv_dac &= ~DAC_B_MASK;
+ tv_dac &= ~DAC_C_MASK;
+ tv_dac |= (TVDAC_STATE_CHG_EN |
+ TVDAC_A_SENSE_CTL |
+ TVDAC_B_SENSE_CTL |
+ TVDAC_C_SENSE_CTL |
+ DAC_CTL_OVERRIDE |
+ DAC_A_0_7_V |
+ DAC_B_0_7_V |
+ DAC_C_0_7_V);
+ I915_WRITE(TV_CTL, tv_ctl);
+ I915_WRITE(TV_DAC, tv_dac);
+ intel_wait_for_vblank(dev);
+ tv_dac = I915_READ(TV_DAC);
+ I915_WRITE(TV_DAC, save_tv_dac);
+ I915_WRITE(TV_CTL, save_tv_ctl);
+ intel_wait_for_vblank(dev);
/*
* A B C
* 0 1 1 Composite
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index f30aa7274a5..f97563db4e5 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -35,6 +35,23 @@
#include "atom.h"
/*
+ * Clear GPU surface registers.
+ */
+static void radeon_surface_init(struct radeon_device *rdev)
+{
+ /* FIXME: check this out */
+ if (rdev->family < CHIP_R600) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ WREG32(RADEON_SURFACE0_INFO +
+ i * (RADEON_SURFACE1_INFO - RADEON_SURFACE0_INFO),
+ 0);
+ }
+ }
+}
+
+/*
* GPU scratch registers helpers function.
*/
static void radeon_scratch_init(struct radeon_device *rdev)
@@ -496,6 +513,8 @@ int radeon_device_init(struct radeon_device *rdev,
radeon_errata(rdev);
/* Initialize scratch registers */
radeon_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
/* TODO: disable VGA need to use VGA request */
/* BIOS*/
@@ -604,9 +623,6 @@ int radeon_device_init(struct radeon_device *rdev,
if (r) {
return r;
}
- if (rdev->fbdev_rfb && rdev->fbdev_rfb->obj) {
- rdev->fbdev_robj = rdev->fbdev_rfb->obj->driver_private;
- }
if (!ret) {
DRM_INFO("radeon: kernel modesetting successfully initialized.\n");
}
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 09c9fb9f621..84ba69f4878 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -345,7 +345,7 @@ static void __exit radeon_exit(void)
drm_exit(driver);
}
-late_initcall(radeon_init);
+module_init(radeon_init);
module_exit(radeon_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index fa86d398945..9e8f191eb64 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -478,14 +478,16 @@ int radeonfb_create(struct radeon_device *rdev,
{
struct fb_info *info;
struct radeon_fb_device *rfbdev;
- struct drm_framebuffer *fb;
+ struct drm_framebuffer *fb = NULL;
struct radeon_framebuffer *rfb;
struct drm_mode_fb_cmd mode_cmd;
struct drm_gem_object *gobj = NULL;
struct radeon_object *robj = NULL;
struct device *device = &rdev->pdev->dev;
int size, aligned_size, ret;
+ u64 fb_gpuaddr;
void *fbptr = NULL;
+ unsigned long tmp;
mode_cmd.width = surface_width;
mode_cmd.height = surface_height;
@@ -498,11 +500,12 @@ int radeonfb_create(struct radeon_device *rdev,
aligned_size = ALIGN(size, PAGE_SIZE);
ret = radeon_gem_object_create(rdev, aligned_size, 0,
- RADEON_GEM_DOMAIN_VRAM,
- false, ttm_bo_type_kernel,
- false, &gobj);
+ RADEON_GEM_DOMAIN_VRAM,
+ false, ttm_bo_type_kernel,
+ false, &gobj);
if (ret) {
- printk(KERN_ERR "failed to allocate framebuffer\n");
+ printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
+ surface_width, surface_height);
ret = -ENOMEM;
goto out;
}
@@ -515,12 +518,19 @@ int radeonfb_create(struct radeon_device *rdev,
ret = -ENOMEM;
goto out_unref;
}
+ ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
+ if (ret) {
+ printk(KERN_ERR "failed to pin framebuffer\n");
+ ret = -ENOMEM;
+ goto out_unref;
+ }
list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
rfb = to_radeon_framebuffer(fb);
*rfb_p = rfb;
rdev->fbdev_rfb = rfb;
+ rdev->fbdev_robj = robj;
info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
if (info == NULL) {
@@ -541,13 +551,13 @@ int radeonfb_create(struct radeon_device *rdev,
info->fix.xpanstep = 1; /* doing it in hw */
info->fix.ypanstep = 1; /* doing it in hw */
info->fix.ywrapstep = 0;
- info->fix.accel = FB_ACCEL_I830;
+ info->fix.accel = FB_ACCEL_NONE;
info->fix.type_aux = 0;
info->flags = FBINFO_DEFAULT;
info->fbops = &radeonfb_ops;
info->fix.line_length = fb->pitch;
- info->screen_base = fbptr;
- info->fix.smem_start = (unsigned long)fbptr;
+ tmp = fb_gpuaddr - rdev->mc.vram_location;
+ info->fix.smem_start = rdev->mc.aper_base + tmp;
info->fix.smem_len = size;
info->screen_base = fbptr;
info->screen_size = size;
@@ -562,8 +572,8 @@ int radeonfb_create(struct radeon_device *rdev,
info->var.width = -1;
info->var.xres = fb_width;
info->var.yres = fb_height;
- info->fix.mmio_start = pci_resource_start(rdev->pdev, 2);
- info->fix.mmio_len = pci_resource_len(rdev->pdev, 2);
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
info->pixmap.size = 64*1024;
info->pixmap.buf_align = 8;
info->pixmap.access_align = 32;
@@ -644,7 +654,7 @@ out_unref:
if (robj) {
radeon_object_kunmap(robj);
}
- if (ret) {
+ if (fb && ret) {
list_del(&fb->filp_head);
drm_gem_object_unreference(gobj);
drm_framebuffer_cleanup(fb);
@@ -813,6 +823,7 @@ int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
robj = rfb->obj->driver_private;
unregister_framebuffer(info);
radeon_object_kunmap(robj);
+ radeon_object_unpin(robj);
framebuffer_release(info);
}
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 983e8df5e00..bac0d06c52a 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -223,7 +223,6 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
{
uint32_t flags;
uint32_t tmp;
- void *fbptr;
int r;
flags = radeon_object_flags_from_domain(domain);
@@ -242,10 +241,6 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
DRM_ERROR("radeon: failed to reserve object for pinning it.\n");
return r;
}
- if (robj->rdev->fbdev_robj == robj) {
- mutex_lock(&robj->rdev->fbdev_info->lock);
- radeon_object_kunmap(robj);
- }
tmp = robj->tobj.mem.placement;
ttm_flag_masked(&tmp, flags, TTM_PL_MASK_MEM);
robj->tobj.proposed_placement = tmp | TTM_PL_FLAG_NO_EVICT | TTM_PL_MASK_CACHING;
@@ -261,23 +256,12 @@ int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
DRM_ERROR("radeon: failed to pin object.\n");
}
radeon_object_unreserve(robj);
- if (robj->rdev->fbdev_robj == robj) {
- if (!r) {
- r = radeon_object_kmap(robj, &fbptr);
- }
- if (!r) {
- robj->rdev->fbdev_info->screen_base = fbptr;
- robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr;
- }
- mutex_unlock(&robj->rdev->fbdev_info->lock);
- }
return r;
}
void radeon_object_unpin(struct radeon_object *robj)
{
uint32_t flags;
- void *fbptr;
int r;
spin_lock(&robj->tobj.lock);
@@ -297,10 +281,6 @@ void radeon_object_unpin(struct radeon_object *robj)
DRM_ERROR("radeon: failed to reserve object for unpinning it.\n");
return;
}
- if (robj->rdev->fbdev_robj == robj) {
- mutex_lock(&robj->rdev->fbdev_info->lock);
- radeon_object_kunmap(robj);
- }
flags = robj->tobj.mem.placement;
robj->tobj.proposed_placement = flags & ~TTM_PL_FLAG_NO_EVICT;
r = ttm_buffer_object_validate(&robj->tobj,
@@ -310,16 +290,6 @@ void radeon_object_unpin(struct radeon_object *robj)
DRM_ERROR("radeon: failed to unpin buffer.\n");
}
radeon_object_unreserve(robj);
- if (robj->rdev->fbdev_robj == robj) {
- if (!r) {
- r = radeon_object_kmap(robj, &fbptr);
- }
- if (!r) {
- robj->rdev->fbdev_info->screen_base = fbptr;
- robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr;
- }
- mutex_unlock(&robj->rdev->fbdev_info->lock);
- }
}
int radeon_object_wait(struct radeon_object *robj)
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 517c8455963..bdec583901e 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -34,7 +34,6 @@
#include <linux/highmem.h>
#include <linux/wait.h>
#include <linux/vmalloc.h>
-#include <linux/version.h>
#include <linux/module.h>
void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
index 27b146c54fb..40b75032ea4 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_vm.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c
@@ -32,7 +32,6 @@
#include <ttm/ttm_bo_driver.h>
#include <ttm/ttm_placement.h>
#include <linux/mm.h>
-#include <linux/version.h>
#include <linux/rbtree.h>
#include <linux/module.h>
#include <linux/uaccess.h>
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index 0331fa74cd3..75dc8bd2459 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -28,7 +28,6 @@
* Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
*/
-#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/highmem.h>
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index aa87b6a3bbe..8206442fbab 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -328,6 +328,7 @@ config I2C_DAVINCI
config I2C_DESIGNWARE
tristate "Synopsys DesignWare"
+ depends on HAVE_CLK
help
If you say yes to this option, support will be included for the
Synopsys DesignWare I2C adapter. Only master mode is supported.
diff --git a/drivers/ide/cs5520.c b/drivers/ide/cs5520.c
index bd066bb9d61..09f98ed0731 100644
--- a/drivers/ide/cs5520.c
+++ b/drivers/ide/cs5520.c
@@ -135,6 +135,7 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
hw[0].irq = 14;
+ hw[1].irq = 15;
return ide_host_add(d, hws, 2, NULL);
}
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 77f79d26b26..c509c991646 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -92,6 +92,11 @@ int ide_acpi_init(void)
return 0;
}
+bool ide_port_acpi(ide_hwif_t *hwif)
+{
+ return ide_noacpi == 0 && hwif->acpidata;
+}
+
/**
* ide_get_dev_handle - finds acpi_handle and PCI device.function
* @dev: device to locate
@@ -352,9 +357,6 @@ int ide_acpi_exec_tfs(ide_drive_t *drive)
unsigned long gtf_address;
unsigned long obj_loc;
- if (ide_noacpi)
- return 0;
-
DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
@@ -389,16 +391,6 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
struct acpi_buffer output;
union acpi_object *out_obj;
- if (ide_noacpi)
- return;
-
- DEBPRINT("ENTER:\n");
-
- if (!hwif->acpidata) {
- DEBPRINT("no ACPI data for %s\n", hwif->name);
- return;
- }
-
/* Setting up output buffer for _GTM */
output.length = ACPI_ALLOCATE_BUFFER;
output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
@@ -479,16 +471,6 @@ void ide_acpi_push_timing(ide_hwif_t *hwif)
struct ide_acpi_drive_link *master = &hwif->acpidata->master;
struct ide_acpi_drive_link *slave = &hwif->acpidata->slave;
- if (ide_noacpi)
- return;
-
- DEBPRINT("ENTER:\n");
-
- if (!hwif->acpidata) {
- DEBPRINT("no ACPI data for %s\n", hwif->name);
- return;
- }
-
/* Give the GTM buffer + drive Identify data to the channel via the
* _STM method: */
/* setup input parameters buffer for _STM */
@@ -527,16 +509,11 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
ide_drive_t *drive;
int i;
- if (ide_noacpi || ide_noacpi_psx)
+ if (ide_noacpi_psx)
return;
DEBPRINT("ENTER:\n");
- if (!hwif->acpidata) {
- DEBPRINT("no ACPI data for %s\n", hwif->name);
- return;
- }
-
/* channel first and then drives for power on and verse versa for power off */
if (on)
acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
@@ -616,7 +593,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
drive->name, err);
}
- if (!ide_acpionboot) {
+ if (ide_noacpi || ide_acpionboot == 0) {
DEBPRINT("ACPI methods disabled on boot\n");
return;
}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 4a19686fcfe..6a9a769bffc 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -592,9 +592,19 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
}
} else if (!blk_pc_request(rq)) {
ide_cd_request_sense_fixup(drive, cmd);
- /* complain if we still have data left to transfer */
+
uptodate = cmd->nleft ? 0 : 1;
- if (uptodate == 0)
+
+ /*
+ * suck out the remaining bytes from the drive in an
+ * attempt to complete the data xfer. (see BZ#13399)
+ */
+ if (!(stat & ATA_ERR) && !uptodate && thislen) {
+ ide_pio_bytes(drive, cmd, write, thislen);
+ uptodate = cmd->nleft ? 0 : 1;
+ }
+
+ if (!uptodate)
rq->cmd_flags |= REQ_FAILED;
}
goto out_end;
@@ -876,9 +886,12 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
return stat;
/*
- * Sanity check the given block size
+ * Sanity check the given block size, in so far as making
+ * sure the sectors_per_frame we give to the caller won't
+ * end up being bogus.
*/
blocklen = be32_to_cpu(capbuf.blocklen);
+ blocklen = (blocklen >> SECTOR_BITS) << SECTOR_BITS;
switch (blocklen) {
case 512:
case 1024:
@@ -886,10 +899,9 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
case 4096:
break;
default:
- printk(KERN_ERR PFX "%s: weird block size %u\n",
+ printk_once(KERN_ERR PFX "%s: weird block size %u; "
+ "setting default block size to 2048\n",
drive->name, blocklen);
- printk(KERN_ERR PFX "%s: default to 2kb block size\n",
- drive->name);
blocklen = 2048;
break;
}
diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c
index 5bf958e5b1d..1099bf7cf96 100644
--- a/drivers/ide/ide-devsets.c
+++ b/drivers/ide/ide-devsets.c
@@ -183,6 +183,6 @@ ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
err = setfunc(drive, *(int *)&rq->cmd[1]);
if (err)
rq->errors = err;
- ide_complete_rq(drive, err, ide_rq_bytes(rq));
+ ide_complete_rq(drive, err, blk_rq_bytes(rq));
return ide_stopped;
}
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 219e6fb78dc..ee58c88dee5 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -361,9 +361,6 @@ static int ide_tune_dma(ide_drive_t *drive)
if (__ide_dma_bad_drive(drive))
return 0;
- if (ide_id_dma_bug(drive))
- return 0;
-
if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA)
return config_drive_for_dma(drive);
@@ -394,24 +391,6 @@ static int ide_dma_check(ide_drive_t *drive)
return -1;
}
-int ide_id_dma_bug(ide_drive_t *drive)
-{
- u16 *id = drive->id;
-
- if (id[ATA_ID_FIELD_VALID] & 4) {
- if ((id[ATA_ID_UDMA_MODES] >> 8) &&
- (id[ATA_ID_MWDMA_MODES] >> 8))
- goto err_out;
- } else if ((id[ATA_ID_MWDMA_MODES] >> 8) &&
- (id[ATA_ID_SWDMA_MODES] >> 8))
- goto err_out;
-
- return 0;
-err_out:
- printk(KERN_ERR "%s: bad DMA info in identify block\n", drive->name);
- return 1;
-}
-
int ide_set_dma(ide_drive_t *drive)
{
int rc;
diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c
index 2b914197961..e9abf2c3c33 100644
--- a/drivers/ide/ide-eh.c
+++ b/drivers/ide/ide-eh.c
@@ -149,7 +149,7 @@ static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET) {
if (err <= 0 && rq->errors == 0)
rq->errors = -EIO;
- ide_complete_rq(drive, err ? err : 0, ide_rq_bytes(rq));
+ ide_complete_rq(drive, err ? err : 0, blk_rq_bytes(rq));
}
}
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 8b3f204f7d7..fefbdfc8db0 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -293,7 +293,7 @@ out_end:
drive->failed_pc = NULL;
if (blk_fs_request(rq) == 0 && rq->errors == 0)
rq->errors = -EIO;
- ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
+ ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
return ide_stopped;
}
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 1059f809b80..d5f3c77bead 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -112,16 +112,6 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
}
}
-/* obsolete, blk_rq_bytes() should be used instead */
-unsigned int ide_rq_bytes(struct request *rq)
-{
- if (blk_pc_request(rq))
- return blk_rq_bytes(rq);
- else
- return blk_rq_cur_sectors(rq) << 9;
-}
-EXPORT_SYMBOL_GPL(ide_rq_bytes);
-
int ide_complete_rq(ide_drive_t *drive, int error, unsigned int nr_bytes)
{
ide_hwif_t *hwif = drive->hwif;
@@ -152,14 +142,14 @@ void ide_kill_rq(ide_drive_t *drive, struct request *rq)
if ((media == ide_floppy || media == ide_tape) && drv_req) {
rq->errors = 0;
- ide_complete_rq(drive, 0, blk_rq_bytes(rq));
} else {
if (media == ide_tape)
rq->errors = IDE_DRV_ERROR_GENERAL;
else if (blk_fs_request(rq) == 0 && rq->errors == 0)
rq->errors = -EIO;
- ide_complete_rq(drive, -EIO, ide_rq_bytes(rq));
}
+
+ ide_complete_rq(drive, -EIO, blk_rq_bytes(rq));
}
static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
@@ -476,10 +466,14 @@ void do_ide_request(struct request_queue *q)
if (!ide_lock_port(hwif)) {
ide_hwif_t *prev_port;
-
- WARN_ON_ONCE(hwif->rq);
repeat:
prev_port = hwif->host->cur_port;
+
+ if (drive->dev_flags & IDE_DFLAG_BLOCKED)
+ rq = hwif->rq;
+ else
+ WARN_ON_ONCE(hwif->rq);
+
if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
time_after(drive->sleep, jiffies)) {
ide_unlock_port(hwif);
@@ -506,43 +500,29 @@ repeat:
hwif->cur_dev = drive;
drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
- spin_unlock_irq(&hwif->lock);
- spin_lock_irq(q->queue_lock);
- /*
- * we know that the queue isn't empty, but this can happen
- * if the q->prep_rq_fn() decides to kill a request
- */
- if (!rq)
+ if (rq == NULL) {
+ spin_unlock_irq(&hwif->lock);
+ spin_lock_irq(q->queue_lock);
+ /*
+ * we know that the queue isn't empty, but this can
+ * happen if ->prep_rq_fn() decides to kill a request
+ */
rq = blk_fetch_request(drive->queue);
+ spin_unlock_irq(q->queue_lock);
+ spin_lock_irq(&hwif->lock);
- spin_unlock_irq(q->queue_lock);
- spin_lock_irq(&hwif->lock);
-
- if (!rq) {
- ide_unlock_port(hwif);
- goto out;
+ if (rq == NULL) {
+ ide_unlock_port(hwif);
+ goto out;
+ }
}
/*
* Sanity: don't accept a request that isn't a PM request
- * if we are currently power managed. This is very important as
- * blk_stop_queue() doesn't prevent the blk_fetch_request()
- * above to return us whatever is in the queue. Since we call
- * ide_do_request() ourselves, we end up taking requests while
- * the queue is blocked...
- *
- * We let requests forced at head of queue with ide-preempt
- * though. I hope that doesn't happen too much, hopefully not
- * unless the subdriver triggers such a thing in its own PM
- * state machine.
+ * if we are currently power managed.
*/
- if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
- blk_pm_request(rq) == 0 &&
- (rq->cmd_flags & REQ_PREEMPT) == 0) {
- /* there should be no pending command at this point */
- ide_unlock_port(hwif);
- goto plug_device;
- }
+ BUG_ON((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
+ blk_pm_request(rq) == 0);
hwif->rq = rq;
diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c
index 82f252c3ee6..e246d3d3fbc 100644
--- a/drivers/ide/ide-ioctls.c
+++ b/drivers/ide/ide-ioctls.c
@@ -64,7 +64,8 @@ static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
goto out;
}
- id = kmalloc(size, GFP_KERNEL);
+ /* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */
+ id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
if (id == NULL) {
rc = -ENOMEM;
goto out;
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index fa047150a1c..2892b242bbe 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -210,6 +210,7 @@ EXPORT_SYMBOL_GPL(ide_in_drive_list);
*/
static const struct drive_list_entry ivb_list[] = {
{ "QUANTUM FIREBALLlct10 05" , "A03.0900" },
+ { "QUANTUM FIREBALLlct20 30" , "APL.0900" },
{ "TSSTcorp CDDVDW SH-S202J" , "SB00" },
{ "TSSTcorp CDDVDW SH-S202J" , "SB01" },
{ "TSSTcorp CDDVDW SH-S202N" , "SB00" },
@@ -329,9 +330,6 @@ int ide_driveid_update(ide_drive_t *drive)
kfree(id);
- if ((drive->dev_flags & IDE_DFLAG_USING_DMA) && ide_id_dma_bug(drive))
- ide_dma_off(drive);
-
return 1;
out_err:
if (rc == 2)
diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c
index c14ca144cff..ad7be2669dc 100644
--- a/drivers/ide/ide-pm.c
+++ b/drivers/ide/ide-pm.c
@@ -10,9 +10,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
struct request_pm_state rqpm;
int ret;
- /* call ACPI _GTM only once */
- if ((drive->dn & 1) == 0 || pair == NULL)
- ide_acpi_get_timing(hwif);
+ if (ide_port_acpi(hwif)) {
+ /* call ACPI _GTM only once */
+ if ((drive->dn & 1) == 0 || pair == NULL)
+ ide_acpi_get_timing(hwif);
+ }
memset(&rqpm, 0, sizeof(rqpm));
rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
@@ -26,9 +28,11 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
ret = blk_execute_rq(drive->queue, NULL, rq, 0);
blk_put_request(rq);
- /* call ACPI _PS3 only after both devices are suspended */
- if (ret == 0 && ((drive->dn & 1) || pair == NULL))
- ide_acpi_set_state(hwif, 0);
+ if (ret == 0 && ide_port_acpi(hwif)) {
+ /* call ACPI _PS3 only after both devices are suspended */
+ if ((drive->dn & 1) || pair == NULL)
+ ide_acpi_set_state(hwif, 0);
+ }
return ret;
}
@@ -42,13 +46,15 @@ int generic_ide_resume(struct device *dev)
struct request_pm_state rqpm;
int err;
- /* call ACPI _PS0 / _STM only once */
- if ((drive->dn & 1) == 0 || pair == NULL) {
- ide_acpi_set_state(hwif, 1);
- ide_acpi_push_timing(hwif);
- }
+ if (ide_port_acpi(hwif)) {
+ /* call ACPI _PS0 / _STM only once */
+ if ((drive->dn & 1) == 0 || pair == NULL) {
+ ide_acpi_set_state(hwif, 1);
+ ide_acpi_push_timing(hwif);
+ }
- ide_acpi_exec_tfs(drive);
+ ide_acpi_exec_tfs(drive);
+ }
memset(&rqpm, 0, sizeof(rqpm));
rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 51af4eea0d3..1bb106f6221 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -818,6 +818,24 @@ static int ide_port_setup_devices(ide_hwif_t *hwif)
return j;
}
+static void ide_host_enable_irqs(struct ide_host *host)
+{
+ ide_hwif_t *hwif;
+ int i;
+
+ ide_host_for_each_port(i, hwif, host) {
+ if (hwif == NULL)
+ continue;
+
+ /* clear any pending IRQs */
+ hwif->tp_ops->read_status(hwif);
+
+ /* unmask IRQs */
+ if (hwif->io_ports.ctl_addr)
+ hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
+ }
+}
+
/*
* This routine sets up the IRQ for an IDE interface.
*/
@@ -831,9 +849,6 @@ static int init_irq (ide_hwif_t *hwif)
if (irq_handler == NULL)
irq_handler = ide_intr;
- if (io_ports->ctl_addr)
- hwif->tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
-
if (request_irq(hwif->irq, irq_handler, sa, hwif->name, hwif))
goto out_up;
@@ -1404,6 +1419,8 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
ide_port_tune_devices(hwif);
}
+ ide_host_enable_irqs(host);
+
ide_host_for_each_port(i, hwif, host) {
if (hwif == NULL)
continue;
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
index 0384144c0b3..c94d2c24c35 100644
--- a/drivers/ieee802154/fakehard.c
+++ b/drivers/ieee802154/fakehard.c
@@ -26,11 +26,17 @@
#include <linux/skbuff.h>
#include <linux/if_arp.h>
-#include <net/ieee802154/af_ieee802154.h>
-#include <net/ieee802154/netdevice.h>
-#include <net/ieee802154/mac_def.h>
-#include <net/ieee802154/nl802154.h>
-
+#include <net/af_ieee802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/ieee802154.h>
+#include <net/nl802154.h>
+
+/**
+ * fake_get_pan_id - Retrieve the PAN ID of the device.
+ * @dev: The network device to retrieve the PAN of.
+ *
+ * Return the ID of the PAN from the PIB.
+ */
static u16 fake_get_pan_id(struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
@@ -38,6 +44,14 @@ static u16 fake_get_pan_id(struct net_device *dev)
return 0xeba1;
}
+/**
+ * fake_get_short_addr - Retrieve the short address of the device.
+ * @dev: The network device to retrieve the short address of.
+ *
+ * Returns the IEEE 802.15.4 short-form address cached for this
+ * device. If the device has not yet had a short address assigned
+ * then this should return 0xFFFF to indicate a lack of association.
+ */
static u16 fake_get_short_addr(struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
@@ -45,6 +59,19 @@ static u16 fake_get_short_addr(struct net_device *dev)
return 0x1;
}
+/**
+ * fake_get_dsn - Retrieve the DSN of the device.
+ * @dev: The network device to retrieve the DSN for.
+ *
+ * Returns the IEEE 802.15.4 DSN for the network device.
+ * The DSN is the sequence number which will be added to each
+ * packet or MAC command frame by the MAC during transmission.
+ *
+ * DSN means 'Data Sequence Number'.
+ *
+ * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
+ * document.
+ */
static u8 fake_get_dsn(struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
@@ -52,6 +79,19 @@ static u8 fake_get_dsn(struct net_device *dev)
return 0x00; /* DSN are implemented in HW, so return just 0 */
}
+/**
+ * fake_get_bsn - Retrieve the BSN of the device.
+ * @dev: The network device to retrieve the BSN for.
+ *
+ * Returns the IEEE 802.15.4 BSN for the network device.
+ * The BSN is the sequence number which will be added to each
+ * beacon frame sent by the MAC.
+ *
+ * BSN means 'Beacon Sequence Number'.
+ *
+ * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006
+ * document.
+ */
static u8 fake_get_bsn(struct net_device *dev)
{
BUG_ON(dev->type != ARPHRD_IEEE802154);
@@ -59,6 +99,19 @@ static u8 fake_get_bsn(struct net_device *dev)
return 0x00; /* BSN are implemented in HW, so return just 0 */
}
+/**
+ * fake_assoc_req - Make an association request to the HW.
+ * @dev: The network device which we are associating to a network.
+ * @addr: The coordinator with which we wish to associate.
+ * @channel: The channel on which to associate.
+ * @cap: The capability information field to use in the association.
+ *
+ * Start an association with a coordinator. The coordinator's address
+ * and PAN ID can be found in @addr.
+ *
+ * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE
+ * 802.15.4-2006 document.
+ */
static int fake_assoc_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 channel, u8 cap)
{
@@ -67,18 +120,70 @@ static int fake_assoc_req(struct net_device *dev,
IEEE802154_SUCCESS);
}
+/**
+ * fake_assoc_resp - Send an association response to a device.
+ * @dev: The network device on which to send the response.
+ * @addr: The address of the device to respond to.
+ * @short_addr: The assigned short address for the device (if any).
+ * @status: The result of the association request.
+ *
+ * Queue the association response of the coordinator to another
+ * device's attempt to associate with the network which we
+ * coordinate. This is then added to the indirect-send queue to be
+ * transmitted to the end device when it polls for data.
+ *
+ * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE
+ * 802.15.4-2006 document.
+ */
static int fake_assoc_resp(struct net_device *dev,
struct ieee802154_addr *addr, u16 short_addr, u8 status)
{
return 0;
}
+/**
+ * fake_disassoc_req - Disassociate a device from a network.
+ * @dev: The network device on which we're disassociating a device.
+ * @addr: The device to disassociate from the network.
+ * @reason: The reason to give to the device for being disassociated.
+ *
+ * This sends a disassociation notification to the device being
+ * disassociated from the network.
+ *
+ * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006
+ * document, with the reason described in 7.3.3.2.
+ */
static int fake_disassoc_req(struct net_device *dev,
struct ieee802154_addr *addr, u8 reason)
{
return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS);
}
+/**
+ * fake_start_req - Start an IEEE 802.15.4 PAN.
+ * @dev: The network device on which to start the PAN.
+ * @addr: The coordinator address to use when starting the PAN.
+ * @channel: The channel on which to start the PAN.
+ * @bcn_ord: Beacon order.
+ * @sf_ord: Superframe order.
+ * @pan_coord: Whether or not we are the PAN coordinator or just
+ * requesting a realignment perhaps?
+ * @blx: Battery Life Extension feature bitfield.
+ * @coord_realign: Something to realign something else.
+ *
+ * If pan_coord is non-zero then this starts a network with the
+ * provided parameters, otherwise it attempts a coordinator
+ * realignment of the stated network instead.
+ *
+ * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
+ * document, with 7.3.8 describing coordinator realignment.
+ *
+ * Note: There is currently no way to notify the coordinator userland
+ * program of whether or not the PAN has started successfully. As
+ * such, the coordinator program cannot know when the MAC has
+ * completed starting the network and will simply have to assume
+ * completeness based on some form of time delay.
+ */
static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
u8 channel,
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
@@ -87,6 +192,21 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
return 0;
}
+/**
+ * fake_scan_req - Start a channel scan.
+ * @dev: The network device on which to perform a channel scan.
+ * @type: The type of scan to perform.
+ * @channels: The channel bitmask to scan.
+ * @duration: How long to spend on each channel.
+ *
+ * This starts either a passive (energy) scan or an active (PAN) scan
+ * on the channels indicated in the @channels bitmask. The duration of
+ * the scan is measured in terms of superframe duration. Specifically,
+ * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each
+ * channel.
+ *
+ * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document.
+ */
static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
u8 duration)
{
@@ -132,7 +252,7 @@ static int ieee802154_fake_xmit(struct sk_buff *skb, struct net_device *dev)
/* FIXME: do hardware work here ... */
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c
index 2adf9cb265d..d114d3a9e1e 100644
--- a/drivers/input/misc/cobalt_btns.c
+++ b/drivers/input/misc/cobalt_btns.c
@@ -1,7 +1,7 @@
/*
* Cobalt button interface driver.
*
- * Copyright (C) 2007-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2007-2008 Yoichi Yuasa <yuasa@linux-mips.org>
*
* 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
@@ -148,7 +148,7 @@ static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
return 0;
}
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
MODULE_DESCRIPTION("Cobalt button interface driver");
MODULE_LICENSE("GPL");
/* work with hotplug and coldplug */
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index 02bdca6f95c..022a1945295 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -21,8 +21,6 @@ menuconfig ISDN
if ISDN
-source "drivers/isdn/mISDN/Kconfig"
-
menuconfig ISDN_I4L
tristate "Old ISDN4Linux (deprecated)"
---help---
@@ -41,9 +39,9 @@ menuconfig ISDN_I4L
It is still available, though, for use with adapters that are not
supported by the new CAPI subsystem yet.
-if ISDN_I4L
+source "drivers/isdn/mISDN/Kconfig"
+
source "drivers/isdn/i4l/Kconfig"
-endif
menuconfig ISDN_CAPI
tristate "CAPI 2.0 subsystem"
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
index 946c38cf6f8..1f0a9490646 100644
--- a/drivers/isdn/act2000/capi.c
+++ b/drivers/isdn/act2000/capi.c
@@ -78,7 +78,6 @@ static actcapi_msgdsc valid_msg[] = {
#endif
{{ 0x00, 0x00}, NULL},
};
-#define num_valid_msg (sizeof(valid_msg)/sizeof(actcapi_msgdsc))
#define num_valid_imsg 27 /* MANUFACTURER_IND */
/*
@@ -1025,7 +1024,7 @@ actcapi_debug_msg(struct sk_buff *skb, int direction)
#ifdef DEBUG_DUMP_SKB
dump_skb(skb);
#endif
- for (i = 0; i < num_valid_msg; i++)
+ for (i = 0; i < ARRAY_SIZE(valid_msg); i++)
if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
(msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
descr = valid_msg[i].description;
diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c
index 8325022e2be..f774e12bb64 100644
--- a/drivers/isdn/act2000/module.c
+++ b/drivers/isdn/act2000/module.c
@@ -23,7 +23,6 @@ static unsigned short act2000_isa_ports[] =
0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
};
-#define ISA_NRPORTS (sizeof(act2000_isa_ports)/sizeof(unsigned short))
static act2000_card *cards = (act2000_card *) NULL;
@@ -686,21 +685,21 @@ act2000_addcard(int bus, int port, int irq, char *id)
* This may result in more than one card detected.
*/
switch (bus) {
- case ACT2000_BUS_ISA:
- for (i = 0; i < ISA_NRPORTS; i++)
- if (act2000_isa_detect(act2000_isa_ports[i])) {
- printk(KERN_INFO
- "act2000: Detected ISA card at port 0x%x\n",
- act2000_isa_ports[i]);
- act2000_alloccard(bus, act2000_isa_ports[i], irq, id);
- }
- break;
- case ACT2000_BUS_MCA:
- case ACT2000_BUS_PCMCIA:
- default:
- printk(KERN_WARNING
- "act2000: addcard: Invalid BUS type %d\n",
- bus);
+ case ACT2000_BUS_ISA:
+ for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++)
+ if (act2000_isa_detect(act2000_isa_ports[i])) {
+ printk(KERN_INFO "act2000: Detected "
+ "ISA card at port 0x%x\n",
+ act2000_isa_ports[i]);
+ act2000_alloccard(bus,
+ act2000_isa_ports[i], irq, id);
+ }
+ break;
+ case ACT2000_BUS_MCA:
+ case ACT2000_BUS_PCMCIA:
+ default:
+ printk(KERN_WARNING
+ "act2000: addcard: Invalid BUS type %d\n", bus);
}
}
if (!cards)
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index 31f91c18c69..27d5dd68f4f 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -551,9 +551,7 @@ word api_put(APPL * appl, CAPI_MSG * msg)
dbug(1,dprintf("com=%x",msg->header.command));
for(j=0;j<MAX_MSG_PARMS+1;j++) msg_parms[j].length = 0;
- for(i=0, ret = _BAD_MSG;
- i<(sizeof(ftable)/sizeof(struct _ftable));
- i++) {
+ for(i=0, ret = _BAD_MSG; i < ARRAY_SIZE(ftable); i++) {
if(ftable[i].command==msg->header.command) {
/* break loop if the message is correct, otherwise continue scan */
diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c
index c964b8d91ad..cb7616c5b60 100644
--- a/drivers/isdn/hardware/eicon/os_4bri.c
+++ b/drivers/isdn/hardware/eicon/os_4bri.c
@@ -149,8 +149,7 @@ int diva_4bri_init_card(diva_os_xdi_adapter_t * a)
diva_os_xdi_adapter_t *diva_current;
diva_os_xdi_adapter_t *adapter_list[4];
PISDN_ADAPTER Slave;
- unsigned long bar_length[sizeof(_4bri_bar_length) /
- sizeof(_4bri_bar_length[0])];
+ unsigned long bar_length[ARRAY_SIZE(_4bri_bar_length)];
int v2 = _4bri_is_rev_2_card(a->CardOrdinal);
int tasks = _4bri_is_rev_2_bri_card(a->CardOrdinal) ? 1 : MQ_INSTANCE_COUNT;
int factor = (tasks == 1) ? 1 : 2;
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index 3024566dd09..bde55d7287f 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -39,3 +39,54 @@ config MISDN_HFCUSB
Enable support for USB ISDN TAs with Cologne Chip AG's
HFC-S USB ISDN Controller
+config MISDN_AVMFRITZ
+ tristate "Support for AVM FRITZ!CARD PCI"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ help
+ Enable support for AVMs FRITZ!CARD PCI cards
+
+config MISDN_SPEEDFAX
+ tristate "Support for Sedlbauer Speedfax+"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ select MISDN_ISAR
+ help
+ Enable support for Sedlbauer Speedfax+.
+
+config MISDN_INFINEON
+ tristate "Support for cards with Infineon chipset"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ help
+ Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX
+ chip from Infineon (former manufacturer Siemens).
+
+config MISDN_W6692
+ tristate "Support for cards with Winbond 6692"
+ depends on MISDN
+ depends on PCI
+ help
+ Enable support for Winbond 6692 PCI chip based cards.
+
+config MISDN_NETJET
+ tristate "Support for NETJet cards"
+ depends on MISDN
+ depends on PCI
+ select MISDN_IPAC
+ select ISDN_HDLC
+ help
+ Enable support for Traverse Technologies NETJet PCI cards.
+
+
+config MISDN_IPAC
+ tristate
+ depends on MISDN
+
+config MISDN_ISAR
+ tristate
+ depends on MISDN
+
diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile
index b0403526bbb..2987d990993 100644
--- a/drivers/isdn/hardware/mISDN/Makefile
+++ b/drivers/isdn/hardware/mISDN/Makefile
@@ -6,3 +6,11 @@
obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o
obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o
obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o
+obj-$(CONFIG_MISDN_AVMFRITZ) += avmfritz.o
+obj-$(CONFIG_MISDN_SPEEDFAX) += speedfax.o
+obj-$(CONFIG_MISDN_INFINEON) += mISDNinfineon.o
+obj-$(CONFIG_MISDN_W6692) += w6692.o
+obj-$(CONFIG_MISDN_NETJET) += netjet.o
+# chip modules
+obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o
+obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o
diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c
new file mode 100644
index 00000000000..81ac541d40d
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/avmfritz.c
@@ -0,0 +1,1152 @@
+/*
+ * avm_fritz.c low level stuff for AVM FRITZ!CARD PCI ISDN cards
+ * Thanks to AVM, Berlin for informations
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include <asm/unaligned.h>
+#include "ipac.h"
+
+
+#define AVMFRITZ_REV "2.1"
+
+static int AVM_cnt;
+static int debug;
+
+enum {
+ AVM_FRITZ_PCI,
+ AVM_FRITZ_PCIV2,
+};
+
+#define HDLC_FIFO 0x0
+#define HDLC_STATUS 0x4
+#define CHIP_WINDOW 0x10
+
+#define CHIP_INDEX 0x4
+#define AVM_HDLC_1 0x00
+#define AVM_HDLC_2 0x01
+#define AVM_ISAC_FIFO 0x02
+#define AVM_ISAC_REG_LOW 0x04
+#define AVM_ISAC_REG_HIGH 0x06
+
+#define AVM_STATUS0_IRQ_ISAC 0x01
+#define AVM_STATUS0_IRQ_HDLC 0x02
+#define AVM_STATUS0_IRQ_TIMER 0x04
+#define AVM_STATUS0_IRQ_MASK 0x07
+
+#define AVM_STATUS0_RESET 0x01
+#define AVM_STATUS0_DIS_TIMER 0x02
+#define AVM_STATUS0_RES_TIMER 0x04
+#define AVM_STATUS0_ENA_IRQ 0x08
+#define AVM_STATUS0_TESTBIT 0x10
+
+#define AVM_STATUS1_INT_SEL 0x0f
+#define AVM_STATUS1_ENA_IOM 0x80
+
+#define HDLC_MODE_ITF_FLG 0x01
+#define HDLC_MODE_TRANS 0x02
+#define HDLC_MODE_CCR_7 0x04
+#define HDLC_MODE_CCR_16 0x08
+#define HDLC_MODE_TESTLOOP 0x80
+
+#define HDLC_INT_XPR 0x80
+#define HDLC_INT_XDU 0x40
+#define HDLC_INT_RPR 0x20
+#define HDLC_INT_MASK 0xE0
+
+#define HDLC_STAT_RME 0x01
+#define HDLC_STAT_RDO 0x10
+#define HDLC_STAT_CRCVFRRAB 0x0E
+#define HDLC_STAT_CRCVFR 0x06
+#define HDLC_STAT_RML_MASK 0x3f00
+
+#define HDLC_CMD_XRS 0x80
+#define HDLC_CMD_XME 0x01
+#define HDLC_CMD_RRS 0x20
+#define HDLC_CMD_XML_MASK 0x3f00
+#define HDLC_FIFO_SIZE 32
+
+/* Fritz PCI v2.0 */
+
+#define AVM_HDLC_FIFO_1 0x10
+#define AVM_HDLC_FIFO_2 0x18
+
+#define AVM_HDLC_STATUS_1 0x14
+#define AVM_HDLC_STATUS_2 0x1c
+
+#define AVM_ISACX_INDEX 0x04
+#define AVM_ISACX_DATA 0x08
+
+/* data struct */
+#define LOG_SIZE 63
+
+struct hdlc_stat_reg {
+#ifdef __BIG_ENDIAN
+ u8 fill;
+ u8 mode;
+ u8 xml;
+ u8 cmd;
+#else
+ u8 cmd;
+ u8 xml;
+ u8 mode;
+ u8 fill;
+#endif
+} __attribute__((packed));
+
+struct hdlc_hw {
+ union {
+ u32 ctrl;
+ struct hdlc_stat_reg sr;
+ } ctrl;
+ u32 stat;
+};
+
+struct fritzcard {
+ struct list_head list;
+ struct pci_dev *pdev;
+ char name[MISDN_MAX_IDLEN];
+ u8 type;
+ u8 ctrlreg;
+ u16 irq;
+ u32 irqcnt;
+ u32 addr;
+ spinlock_t lock; /* hw lock */
+ struct isac_hw isac;
+ struct hdlc_hw hdlc[2];
+ struct bchannel bch[2];
+ char log[LOG_SIZE + 1];
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static void
+_set_debug(struct fritzcard *card)
+{
+ card->isac.dch.debug = debug;
+ card->bch[0].debug = debug;
+ card->bch[1].debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct fritzcard *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(AVMFRITZ_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "avmfritz debug mask");
+
+/* Interface functions */
+
+static u8
+ReadISAC_V1(void *p, u8 offset)
+{
+ struct fritzcard *fc = p;
+ u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+
+ outb(idx, fc->addr + CHIP_INDEX);
+ return inb(fc->addr + CHIP_WINDOW + (offset & 0xf));
+}
+
+static void
+WriteISAC_V1(void *p, u8 offset, u8 value)
+{
+ struct fritzcard *fc = p;
+ u8 idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
+
+ outb(idx, fc->addr + CHIP_INDEX);
+ outb(value, fc->addr + CHIP_WINDOW + (offset & 0xf));
+}
+
+static void
+ReadFiFoISAC_V1(void *p, u8 off, u8 *data, int size)
+{
+ struct fritzcard *fc = p;
+
+ outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX);
+ insb(fc->addr + CHIP_WINDOW, data, size);
+}
+
+static void
+WriteFiFoISAC_V1(void *p, u8 off, u8 *data, int size)
+{
+ struct fritzcard *fc = p;
+
+ outb(AVM_ISAC_FIFO, fc->addr + CHIP_INDEX);
+ outsb(fc->addr + CHIP_WINDOW, data, size);
+}
+
+static u8
+ReadISAC_V2(void *p, u8 offset)
+{
+ struct fritzcard *fc = p;
+
+ outl(offset, fc->addr + AVM_ISACX_INDEX);
+ return 0xff & inl(fc->addr + AVM_ISACX_DATA);
+}
+
+static void
+WriteISAC_V2(void *p, u8 offset, u8 value)
+{
+ struct fritzcard *fc = p;
+
+ outl(offset, fc->addr + AVM_ISACX_INDEX);
+ outl(value, fc->addr + AVM_ISACX_DATA);
+}
+
+static void
+ReadFiFoISAC_V2(void *p, u8 off, u8 *data, int size)
+{
+ struct fritzcard *fc = p;
+ int i;
+
+ outl(off, fc->addr + AVM_ISACX_INDEX);
+ for (i = 0; i < size; i++)
+ data[i] = 0xff & inl(fc->addr + AVM_ISACX_DATA);
+}
+
+static void
+WriteFiFoISAC_V2(void *p, u8 off, u8 *data, int size)
+{
+ struct fritzcard *fc = p;
+ int i;
+
+ outl(off, fc->addr + AVM_ISACX_INDEX);
+ for (i = 0; i < size; i++)
+ outl(data[i], fc->addr + AVM_ISACX_DATA);
+}
+
+static struct bchannel *
+Sel_BCS(struct fritzcard *fc, u32 channel)
+{
+ if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) &&
+ (fc->bch[0].nr & channel))
+ return &fc->bch[0];
+ else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) &&
+ (fc->bch[1].nr & channel))
+ return &fc->bch[1];
+ else
+ return NULL;
+}
+
+static inline void
+__write_ctrl_pci(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) {
+ u32 idx = channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1;
+
+ outl(idx, fc->addr + CHIP_INDEX);
+ outl(hdlc->ctrl.ctrl, fc->addr + CHIP_WINDOW + HDLC_STATUS);
+}
+
+static inline void
+__write_ctrl_pciv2(struct fritzcard *fc, struct hdlc_hw *hdlc, u32 channel) {
+ outl(hdlc->ctrl.ctrl, fc->addr + (channel == 2 ? AVM_HDLC_STATUS_2 :
+ AVM_HDLC_STATUS_1));
+}
+
+void
+write_ctrl(struct bchannel *bch, int which) {
+ struct fritzcard *fc = bch->hw;
+ struct hdlc_hw *hdlc;
+
+ hdlc = &fc->hdlc[(bch->nr - 1) & 1];
+ pr_debug("%s: hdlc %c wr%x ctrl %x\n", fc->name, '@' + bch->nr,
+ which, hdlc->ctrl.ctrl);
+ switch (fc->type) {
+ case AVM_FRITZ_PCIV2:
+ __write_ctrl_pciv2(fc, hdlc, bch->nr);
+ break;
+ case AVM_FRITZ_PCI:
+ __write_ctrl_pci(fc, hdlc, bch->nr);
+ break;
+ }
+}
+
+
+static inline u32
+__read_status_pci(u_long addr, u32 channel)
+{
+ outl(channel == 2 ? AVM_HDLC_2 : AVM_HDLC_1, addr + CHIP_INDEX);
+ return inl(addr + CHIP_WINDOW + HDLC_STATUS);
+}
+
+static inline u32
+__read_status_pciv2(u_long addr, u32 channel)
+{
+ return inl(addr + (channel == 2 ? AVM_HDLC_STATUS_2 :
+ AVM_HDLC_STATUS_1));
+}
+
+
+static u32
+read_status(struct fritzcard *fc, u32 channel)
+{
+ switch (fc->type) {
+ case AVM_FRITZ_PCIV2:
+ return __read_status_pciv2(fc->addr, channel);
+ case AVM_FRITZ_PCI:
+ return __read_status_pci(fc->addr, channel);
+ }
+ /* dummy */
+ return 0;
+}
+
+static void
+enable_hwirq(struct fritzcard *fc)
+{
+ fc->ctrlreg |= AVM_STATUS0_ENA_IRQ;
+ outb(fc->ctrlreg, fc->addr + 2);
+}
+
+static void
+disable_hwirq(struct fritzcard *fc)
+{
+ fc->ctrlreg &= ~AVM_STATUS0_ENA_IRQ;
+ outb(fc->ctrlreg, fc->addr + 2);
+}
+
+static int
+modehdlc(struct bchannel *bch, int protocol)
+{
+ struct fritzcard *fc = bch->hw;
+ struct hdlc_hw *hdlc;
+
+ hdlc = &fc->hdlc[(bch->nr - 1) & 1];
+ pr_debug("%s: hdlc %c protocol %x-->%x ch %d\n", fc->name,
+ '@' + bch->nr, bch->state, protocol, bch->nr);
+ hdlc->ctrl.ctrl = 0;
+ switch (protocol) {
+ case -1: /* used for init */
+ bch->state = -1;
+ case ISDN_P_NONE:
+ if (bch->state == ISDN_P_NONE)
+ break;
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
+ hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+ write_ctrl(bch, 5);
+ bch->state = ISDN_P_NONE;
+ test_and_clear_bit(FLG_HDLC, &bch->Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
+ break;
+ case ISDN_P_B_RAW:
+ bch->state = protocol;
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
+ hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
+ write_ctrl(bch, 5);
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
+ write_ctrl(bch, 1);
+ hdlc->ctrl.sr.cmd = 0;
+ test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ bch->state = protocol;
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
+ hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+ write_ctrl(bch, 5);
+ hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
+ write_ctrl(bch, 1);
+ hdlc->ctrl.sr.cmd = 0;
+ test_and_set_bit(FLG_HDLC, &bch->Flags);
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", fc->name, protocol);
+ return -ENOPROTOOPT;
+ }
+ return 0;
+}
+
+static void
+hdlc_empty_fifo(struct bchannel *bch, int count)
+{
+ u32 *ptr;
+ u8 *p;
+ u32 val, addr;
+ int cnt = 0;
+ struct fritzcard *fc = bch->hw;
+
+ pr_debug("%s: %s %d\n", fc->name, __func__, count);
+ if (!bch->rx_skb) {
+ bch->rx_skb = mI_alloc_skb(bch->maxlen, GFP_ATOMIC);
+ if (!bch->rx_skb) {
+ pr_info("%s: B receive out of memory\n",
+ fc->name);
+ return;
+ }
+ }
+ if ((bch->rx_skb->len + count) > bch->maxlen) {
+ pr_debug("%s: overrun %d\n", fc->name,
+ bch->rx_skb->len + count);
+ return;
+ }
+ p = skb_put(bch->rx_skb, count);
+ ptr = (u32 *)p;
+ if (AVM_FRITZ_PCIV2 == fc->type)
+ addr = fc->addr + (bch->nr == 2 ?
+ AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
+ else {
+ addr = fc->addr + CHIP_WINDOW;
+ outl(bch->nr == 2 ? AVM_HDLC_2 : AVM_HDLC_1, fc->addr);
+ }
+ while (cnt < count) {
+ val = le32_to_cpu(inl(addr));
+ put_unaligned(val, ptr);
+ ptr++;
+ cnt += 4;
+ }
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(fc->log, LOG_SIZE, "B%1d-recv %s %d ",
+ bch->nr, fc->name, count);
+ print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+hdlc_fill_fifo(struct bchannel *bch)
+{
+ struct fritzcard *fc = bch->hw;
+ struct hdlc_hw *hdlc;
+ int count, cnt = 0;
+ u8 *p;
+ u32 *ptr, val, addr;
+
+ hdlc = &fc->hdlc[(bch->nr - 1) & 1];
+ if (!bch->tx_skb)
+ return;
+ count = bch->tx_skb->len - bch->tx_idx;
+ if (count <= 0)
+ return;
+ p = bch->tx_skb->data + bch->tx_idx;
+ hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
+ if (count > HDLC_FIFO_SIZE) {
+ count = HDLC_FIFO_SIZE;
+ } else {
+ if (test_bit(FLG_HDLC, &bch->Flags))
+ hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
+ }
+ pr_debug("%s: %s %d/%d/%d", fc->name, __func__, count,
+ bch->tx_idx, bch->tx_skb->len);
+ ptr = (u32 *)p;
+ bch->tx_idx += count;
+ hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
+ if (AVM_FRITZ_PCIV2 == fc->type) {
+ __write_ctrl_pciv2(fc, hdlc, bch->nr);
+ addr = fc->addr + (bch->nr == 2 ?
+ AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1);
+ } else {
+ __write_ctrl_pci(fc, hdlc, bch->nr);
+ addr = fc->addr + CHIP_WINDOW;
+ }
+ while (cnt < count) {
+ val = get_unaligned(ptr);
+ outl(cpu_to_le32(val), addr);
+ ptr++;
+ cnt += 4;
+ }
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(fc->log, LOG_SIZE, "B%1d-send %s %d ",
+ bch->nr, fc->name, count);
+ print_hex_dump_bytes(fc->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+HDLC_irq_xpr(struct bchannel *bch)
+{
+ if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
+ hdlc_fill_fifo(bch);
+ else {
+ if (bch->tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &bch->Flags))
+ confirm_Bsend(bch);
+ dev_kfree_skb(bch->tx_skb);
+ }
+ if (get_next_bframe(bch))
+ hdlc_fill_fifo(bch);
+ }
+}
+
+static void
+HDLC_irq(struct bchannel *bch, u32 stat)
+{
+ struct fritzcard *fc = bch->hw;
+ int len;
+ struct hdlc_hw *hdlc;
+
+ hdlc = &fc->hdlc[(bch->nr - 1) & 1];
+ pr_debug("%s: ch%d stat %#x\n", fc->name, bch->nr, stat);
+ if (stat & HDLC_INT_RPR) {
+ if (stat & HDLC_STAT_RDO) {
+ hdlc->ctrl.sr.xml = 0;
+ hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
+ write_ctrl(bch, 1);
+ hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
+ write_ctrl(bch, 1);
+ if (bch->rx_skb)
+ skb_trim(bch->rx_skb, 0);
+ } else {
+ len = (stat & HDLC_STAT_RML_MASK) >> 8;
+ if (!len)
+ len = 32;
+ hdlc_empty_fifo(bch, len);
+ if (!bch->rx_skb)
+ goto handle_tx;
+ if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT,
+ &bch->Flags)) {
+ if (((stat & HDLC_STAT_CRCVFRRAB) ==
+ HDLC_STAT_CRCVFR) ||
+ test_bit(FLG_TRANSPARENT, &bch->Flags)) {
+ recv_Bchannel(bch, 0);
+ } else {
+ pr_debug("%s: got invalid frame\n",
+ fc->name);
+ skb_trim(bch->rx_skb, 0);
+ }
+ }
+ }
+ }
+handle_tx:
+ if (stat & HDLC_INT_XDU) {
+ /* Here we lost an TX interrupt, so
+ * restart transmitting the whole frame on HDLC
+ * in transparent mode we send the next data
+ */
+ if (bch->tx_skb)
+ pr_debug("%s: ch%d XDU len(%d) idx(%d) Flags(%lx)\n",
+ fc->name, bch->nr, bch->tx_skb->len,
+ bch->tx_idx, bch->Flags);
+ else
+ pr_debug("%s: ch%d XDU no tx_skb Flags(%lx)\n",
+ fc->name, bch->nr, bch->Flags);
+ if (bch->tx_skb && bch->tx_skb->len) {
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ bch->tx_idx = 0;
+ }
+ hdlc->ctrl.sr.xml = 0;
+ hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS;
+ write_ctrl(bch, 1);
+ hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
+ HDLC_irq_xpr(bch);
+ return;
+ } else if (stat & HDLC_INT_XPR)
+ HDLC_irq_xpr(bch);
+}
+
+static inline void
+HDLC_irq_main(struct fritzcard *fc)
+{
+ u32 stat;
+ struct bchannel *bch;
+
+ stat = read_status(fc, 1);
+ if (stat & HDLC_INT_MASK) {
+ bch = Sel_BCS(fc, 1);
+ if (bch)
+ HDLC_irq(bch, stat);
+ else
+ pr_debug("%s: spurious ch1 IRQ\n", fc->name);
+ }
+ stat = read_status(fc, 2);
+ if (stat & HDLC_INT_MASK) {
+ bch = Sel_BCS(fc, 2);
+ if (bch)
+ HDLC_irq(bch, stat);
+ else
+ pr_debug("%s: spurious ch2 IRQ\n", fc->name);
+ }
+}
+
+static irqreturn_t
+avm_fritz_interrupt(int intno, void *dev_id)
+{
+ struct fritzcard *fc = dev_id;
+ u8 val;
+ u8 sval;
+
+ spin_lock(&fc->lock);
+ sval = inb(fc->addr + 2);
+ pr_debug("%s: irq stat0 %x\n", fc->name, sval);
+ if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
+ /* shared IRQ from other HW */
+ spin_unlock(&fc->lock);
+ return IRQ_NONE;
+ }
+ fc->irqcnt++;
+
+ if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
+ val = ReadISAC_V1(fc, ISAC_ISTA);
+ mISDNisac_irq(&fc->isac, val);
+ }
+ if (!(sval & AVM_STATUS0_IRQ_HDLC))
+ HDLC_irq_main(fc);
+ spin_unlock(&fc->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+avm_fritzv2_interrupt(int intno, void *dev_id)
+{
+ struct fritzcard *fc = dev_id;
+ u8 val;
+ u8 sval;
+
+ spin_lock(&fc->lock);
+ sval = inb(fc->addr + 2);
+ pr_debug("%s: irq stat0 %x\n", fc->name, sval);
+ if (!(sval & AVM_STATUS0_IRQ_MASK)) {
+ /* shared IRQ from other HW */
+ spin_unlock(&fc->lock);
+ return IRQ_NONE;
+ }
+ fc->irqcnt++;
+
+ if (sval & AVM_STATUS0_IRQ_HDLC)
+ HDLC_irq_main(fc);
+ if (sval & AVM_STATUS0_IRQ_ISAC) {
+ val = ReadISAC_V2(fc, ISACX_ISTA);
+ mISDNisac_irq(&fc->isac, val);
+ }
+ if (sval & AVM_STATUS0_IRQ_TIMER) {
+ pr_debug("%s: timer irq\n", fc->name);
+ outb(fc->ctrlreg | AVM_STATUS0_RES_TIMER, fc->addr + 2);
+ udelay(1);
+ outb(fc->ctrlreg, fc->addr + 2);
+ }
+ spin_unlock(&fc->lock);
+ return IRQ_HANDLED;
+}
+
+static int
+avm_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct fritzcard *fc = bch->hw;
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&fc->lock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ hdlc_fill_fifo(bch);
+ ret = 0;
+ spin_unlock_irqrestore(&fc->lock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(&fc->lock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(&fc->lock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = modehdlc(bch, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(&fc->lock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(&fc->lock, flags);
+ mISDN_clear_bchannel(bch);
+ modehdlc(bch, ISDN_P_NONE);
+ spin_unlock_irqrestore(&fc->lock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static void
+inithdlc(struct fritzcard *fc)
+{
+ modehdlc(&fc->bch[0], -1);
+ modehdlc(&fc->bch[1], -1);
+}
+
+void
+clear_pending_hdlc_ints(struct fritzcard *fc)
+{
+ u32 val;
+
+ val = read_status(fc, 1);
+ pr_debug("%s: HDLC 1 STA %x\n", fc->name, val);
+ val = read_status(fc, 2);
+ pr_debug("%s: HDLC 2 STA %x\n", fc->name, val);
+}
+
+static void
+reset_avm(struct fritzcard *fc)
+{
+ switch (fc->type) {
+ case AVM_FRITZ_PCI:
+ fc->ctrlreg = AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER;
+ break;
+ case AVM_FRITZ_PCIV2:
+ fc->ctrlreg = AVM_STATUS0_RESET;
+ break;
+ }
+ if (debug & DEBUG_HW)
+ pr_notice("%s: reset\n", fc->name);
+ disable_hwirq(fc);
+ mdelay(5);
+ switch (fc->type) {
+ case AVM_FRITZ_PCI:
+ fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
+ disable_hwirq(fc);
+ outb(AVM_STATUS1_ENA_IOM, fc->addr + 3);
+ break;
+ case AVM_FRITZ_PCIV2:
+ fc->ctrlreg = 0;
+ disable_hwirq(fc);
+ break;
+ }
+ mdelay(1);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: S0/S1 %x/%x\n", fc->name,
+ inb(fc->addr + 2), inb(fc->addr + 3));
+}
+
+static int
+init_card(struct fritzcard *fc)
+{
+ int ret, cnt = 3;
+ u_long flags;
+
+ reset_avm(fc); /* disable IRQ */
+ if (fc->type == AVM_FRITZ_PCIV2)
+ ret = request_irq(fc->irq, avm_fritzv2_interrupt,
+ IRQF_SHARED, fc->name, fc);
+ else
+ ret = request_irq(fc->irq, avm_fritz_interrupt,
+ IRQF_SHARED, fc->name, fc);
+ if (ret) {
+ pr_info("%s: couldn't get interrupt %d\n",
+ fc->name, fc->irq);
+ return ret;
+ }
+ while (cnt--) {
+ spin_lock_irqsave(&fc->lock, flags);
+ ret = fc->isac.init(&fc->isac);
+ if (ret) {
+ spin_unlock_irqrestore(&fc->lock, flags);
+ pr_info("%s: ISAC init failed with %d\n",
+ fc->name, ret);
+ break;
+ }
+ clear_pending_hdlc_ints(fc);
+ inithdlc(fc);
+ enable_hwirq(fc);
+ /* RESET Receiver and Transmitter */
+ if (AVM_FRITZ_PCIV2 == fc->type) {
+ WriteISAC_V2(fc, ISACX_MASK, 0);
+ WriteISAC_V2(fc, ISACX_CMDRD, 0x41);
+ } else {
+ WriteISAC_V1(fc, ISAC_MASK, 0);
+ WriteISAC_V1(fc, ISAC_CMDR, 0x41);
+ }
+ spin_unlock_irqrestore(&fc->lock, flags);
+ /* Timeout 10ms */
+ msleep_interruptible(10);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IRQ %d count %d\n", fc->name,
+ fc->irq, fc->irqcnt);
+ if (!fc->irqcnt) {
+ pr_info("%s: IRQ(%d) getting no IRQs during init %d\n",
+ fc->name, fc->irq, 3 - cnt);
+ reset_avm(fc);
+ } else
+ return 0;
+ }
+ free_irq(fc->irq, fc);
+ return -EIO;
+}
+
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+ struct fritzcard *fc = bch->hw;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+avm_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct fritzcard *fc = bch->hw;
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(&fc->lock, flags);
+ mISDN_freebchannel(bch);
+ test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+ test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+ modehdlc(bch, ISDN_P_NONE);
+ spin_unlock_irqrestore(&fc->lock, flags);
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(THIS_MODULE);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n", fc->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static int
+channel_ctrl(struct fritzcard *fc, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP;
+ break;
+ case MISDN_CTRL_LOOP:
+ /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+ if (cq->channel < 0 || cq->channel > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = fc->isac.ctrl(&fc->isac, HW_TESTLOOP, cq->channel);
+ break;
+ default:
+ pr_info("%s: %s unknown Op %x\n", fc->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+open_bchannel(struct fritzcard *fc, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &fc->bch[rq->adr.channel - 1];
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+/*
+ * device control function
+ */
+static int
+avm_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct fritzcard *fc = dch->hw;
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: %s cmd:%x %p\n", fc->name, __func__, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = fc->isac.open(&fc->isac, rq);
+ else
+ err = open_bchannel(fc, rq);
+ if (err)
+ break;
+ if (!try_module_get(THIS_MODULE))
+ pr_info("%s: cannot get module\n", fc->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", fc->name, dch->dev.id,
+ __builtin_return_address(0));
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(fc, arg);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x\n",
+ fc->name, __func__, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+int
+setup_fritz(struct fritzcard *fc)
+{
+ u32 val, ver;
+
+ if (!request_region(fc->addr, 32, fc->name)) {
+ pr_info("%s: AVM config port %x-%x already in use\n",
+ fc->name, fc->addr, fc->addr + 31);
+ return -EIO;
+ }
+ switch (fc->type) {
+ case AVM_FRITZ_PCI:
+ val = inl(fc->addr);
+ outl(AVM_HDLC_1, fc->addr + CHIP_INDEX);
+ ver = inl(fc->addr + CHIP_WINDOW + HDLC_STATUS) >> 24;
+ if (debug & DEBUG_HW) {
+ pr_notice("%s: PCI stat %#x\n", fc->name, val);
+ pr_notice("%s: PCI Class %X Rev %d\n", fc->name,
+ val & 0xff, (val >> 8) & 0xff);
+ pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf);
+ }
+ ASSIGN_FUNC(V1, ISAC, fc->isac);
+ fc->isac.type = IPAC_TYPE_ISAC;
+ break;
+ case AVM_FRITZ_PCIV2:
+ val = inl(fc->addr);
+ ver = inl(fc->addr + AVM_HDLC_STATUS_1) >> 24;
+ if (debug & DEBUG_HW) {
+ pr_notice("%s: PCI V2 stat %#x\n", fc->name, val);
+ pr_notice("%s: PCI V2 Class %X Rev %d\n", fc->name,
+ val & 0xff, (val>>8) & 0xff);
+ pr_notice("%s: HDLC version %x\n", fc->name, ver & 0xf);
+ }
+ ASSIGN_FUNC(V2, ISAC, fc->isac);
+ fc->isac.type = IPAC_TYPE_ISACX;
+ break;
+ default:
+ release_region(fc->addr, 32);
+ pr_info("%s: AVM unknown type %d\n", fc->name, fc->type);
+ return -ENODEV;
+ }
+ pr_notice("%s: %s config irq:%d base:0x%X\n", fc->name,
+ (fc->type == AVM_FRITZ_PCI) ? "AVM Fritz!CARD PCI" :
+ "AVM Fritz!CARD PCIv2", fc->irq, fc->addr);
+ return 0;
+}
+
+static void
+release_card(struct fritzcard *card)
+{
+ u_long flags;
+
+ disable_hwirq(card);
+ spin_lock_irqsave(&card->lock, flags);
+ modehdlc(&card->bch[0], ISDN_P_NONE);
+ modehdlc(&card->bch[1], ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ card->isac.release(&card->isac);
+ free_irq(card->irq, card);
+ mISDN_freebchannel(&card->bch[1]);
+ mISDN_freebchannel(&card->bch[0]);
+ mISDN_unregister_device(&card->isac.dch.dev);
+ release_region(card->addr, 32);
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ AVM_cnt--;
+}
+
+static int __devinit
+setup_instance(struct fritzcard *card)
+{
+ int i, err;
+ u_long flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "AVM.%d", AVM_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+
+ _set_debug(card);
+ card->isac.name = card->name;
+ spin_lock_init(&card->lock);
+ card->isac.hwlock = &card->lock;
+ mISDNisac_init(&card->isac, card);
+
+ card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ card->isac.dch.dev.D.ctrl = avm_dctrl;
+ for (i = 0; i < 2; i++) {
+ card->bch[i].nr = i + 1;
+ set_channelmap(i + 1, card->isac.dch.dev.channelmap);
+ mISDN_initbchannel(&card->bch[i], MAX_DATA_MEM);
+ card->bch[i].hw = card;
+ card->bch[i].ch.send = avm_l2l1B;
+ card->bch[i].ch.ctrl = avm_bctrl;
+ card->bch[i].ch.nr = i + 1;
+ list_add(&card->bch[i].ch.list, &card->isac.dch.dev.bchannels);
+ }
+ err = setup_fritz(card);
+ if (err)
+ goto error;
+ err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,
+ card->name);
+ if (err)
+ goto error_reg;
+ err = init_card(card);
+ if (!err) {
+ AVM_cnt++;
+ pr_notice("AVM %d cards installed DEBUG\n", AVM_cnt);
+ return 0;
+ }
+ mISDN_unregister_device(&card->isac.dch.dev);
+error_reg:
+ release_region(card->addr, 32);
+error:
+ card->isac.release(&card->isac);
+ mISDN_freebchannel(&card->bch[1]);
+ mISDN_freebchannel(&card->bch[0]);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ return err;
+}
+
+static int __devinit
+fritzpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ struct fritzcard *card;
+
+ card = kzalloc(sizeof(struct fritzcard), GFP_KERNEL);
+ if (!card) {
+ pr_info("No kmem for fritzcard\n");
+ return err;
+ }
+ if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
+ card->type = AVM_FRITZ_PCIV2;
+ else
+ card->type = AVM_FRITZ_PCI;
+ card->pdev = pdev;
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+
+ pr_notice("mISDN: found adapter %s at %s\n",
+ (char *) ent->driver_data, pci_name(pdev));
+
+ card->addr = pci_resource_start(pdev, 1);
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err)
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit
+fritz_remove_pci(struct pci_dev *pdev)
+{
+ struct fritzcard *card = pci_get_drvdata(pdev);
+
+ if (card)
+ release_card(card);
+ else
+ if (debug)
+ pr_info("%s: drvdata allready removed\n", __func__);
+}
+
+static struct pci_device_id fcpci_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, (unsigned long) "Fritz!Card PCI"},
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, (unsigned long) "Fritz!Card PCI v2" },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, fcpci_ids);
+
+static struct pci_driver fcpci_driver = {
+ .name = "fcpci",
+ .probe = fritzpci_probe,
+ .remove = __devexit_p(fritz_remove_pci),
+ .id_table = fcpci_ids,
+};
+
+static int __init AVM_init(void)
+{
+ int err;
+
+ pr_notice("AVM Fritz PCI driver Rev. %s\n", AVMFRITZ_REV);
+ err = pci_register_driver(&fcpci_driver);
+ return err;
+}
+
+static void __exit AVM_cleanup(void)
+{
+ pci_unregister_driver(&fcpci_driver);
+}
+
+module_init(AVM_init);
+module_exit(AVM_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c
index e1dab30aed3..faed794cf75 100644
--- a/drivers/isdn/hardware/mISDN/hfcmulti.c
+++ b/drivers/isdn/hardware/mISDN/hfcmulti.c
@@ -3416,22 +3416,8 @@ deactivate_bchannel(struct bchannel *bch)
u_long flags;
spin_lock_irqsave(&hc->lock, flags);
- if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
- dev_kfree_skb(bch->next_skb);
- bch->next_skb = NULL;
- }
- if (bch->tx_skb) {
- dev_kfree_skb(bch->tx_skb);
- bch->tx_skb = NULL;
- }
- bch->tx_idx = 0;
- if (bch->rx_skb) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- }
+ mISDN_clear_bchannel(bch);
hc->chan[bch->slot].coeff_count = 0;
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
hc->chan[bch->slot].rx_off = 0;
hc->chan[bch->slot].conf = -1;
mode_hfcmulti(hc, bch->slot, ISDN_P_NONE, -1, 0, -1, 0);
@@ -5384,9 +5370,10 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ent->device == PCI_DEVICE_ID_CCD_HFC8S ||
ent->device == PCI_DEVICE_ID_CCD_HFCE1)) {
printk(KERN_ERR
- "Unknown HFC multiport controller (vendor:%x device:%x "
- "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device,
- ent->subvendor, ent->subdevice);
+ "Unknown HFC multiport controller (vendor:%04x device:%04x "
+ "subvendor:%04x subdevice:%04x)\n", pdev->vendor,
+ pdev->device, pdev->subsystem_vendor,
+ pdev->subsystem_device);
printk(KERN_ERR
"Please contact the driver maintainer for support.\n");
return -ENODEV;
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 228ffbed128..70e6b0e0112 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -1522,22 +1522,8 @@ deactivate_bchannel(struct bchannel *bch)
u_long flags;
spin_lock_irqsave(&hc->lock, flags);
- if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
- dev_kfree_skb(bch->next_skb);
- bch->next_skb = NULL;
- }
- if (bch->tx_skb) {
- dev_kfree_skb(bch->tx_skb);
- bch->tx_skb = NULL;
- }
- bch->tx_idx = 0;
- if (bch->rx_skb) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- }
+ mISDN_clear_bchannel(bch);
mode_hfcpci(bch, bch->nr, ISDN_P_NONE);
- test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
- test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
spin_unlock_irqrestore(&hc->lock, flags);
}
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 6b7704c41b9..fc46a26cb14 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -1809,21 +1809,7 @@ deactivate_bchannel(struct bchannel *bch)
hw->name, __func__, bch->nr);
spin_lock_irqsave(&hw->lock, flags);
- if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
- dev_kfree_skb(bch->next_skb);
- bch->next_skb = NULL;
- }
- if (bch->tx_skb) {
- dev_kfree_skb(bch->tx_skb);
- bch->tx_skb = NULL;
- }
- bch->tx_idx = 0;
- if (bch->rx_skb) {
- dev_kfree_skb(bch->rx_skb);
- bch->rx_skb = NULL;
- }
- clear_bit(FLG_ACTIVE, &bch->Flags);
- clear_bit(FLG_TX_BUSY, &bch->Flags);
+ mISDN_clear_bchannel(bch);
spin_unlock_irqrestore(&hw->lock, flags);
hfcsusb_setup_bch(bch, ISDN_P_NONE);
hfcsusb_stop_endpoint(hw, bch->nr);
diff --git a/drivers/isdn/hardware/mISDN/iohelper.h b/drivers/isdn/hardware/mISDN/iohelper.h
new file mode 100644
index 00000000000..b438981107a
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/iohelper.h
@@ -0,0 +1,109 @@
+/*
+ * iohelper.h
+ * helper for define functions to access ISDN hardware
+ * supported are memory mapped IO
+ * indirect port IO (one port for address, one for data)
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _IOHELPER_H
+#define _IOHELPER_H
+
+typedef u8 (read_reg_func)(void *hwp, u8 offset);
+typedef void (write_reg_func)(void *hwp, u8 offset, u8 value);
+typedef void (fifo_func)(void *hwp, u8 offset, u8 *datap, int size);
+
+struct _ioport {
+ u32 port;
+ u32 ale;
+};
+
+#define IOFUNC_IO(name, hws, ap) \
+ static u8 Read##name##_IO(void *p, u8 off) {\
+ struct hws *hw = p;\
+ return inb(hw->ap.port + off);\
+ } \
+ static void Write##name##_IO(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ outb(val, hw->ap.port + off);\
+ } \
+ static void ReadFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ insb(hw->ap.port + off, dp, size);\
+ } \
+ static void WriteFiFo##name##_IO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outsb(hw->ap.port + off, dp, size);\
+ }
+
+#define IOFUNC_IND(name, hws, ap) \
+ static u8 Read##name##_IND(void *p, u8 off) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ return inb(hw->ap.port);\
+ } \
+ static void Write##name##_IND(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ outb(val, hw->ap.port);\
+ } \
+ static void ReadFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ insb(hw->ap.port, dp, size);\
+ } \
+ static void WriteFiFo##name##_IND(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ outb(off, hw->ap.ale);\
+ outsb(hw->ap.port, dp, size);\
+ }
+
+#define IOFUNC_MEMIO(name, hws, typ, adr) \
+ static u8 Read##name##_MIO(void *p, u8 off) {\
+ struct hws *hw = p;\
+ return readb(((typ *)hw->adr) + off);\
+ } \
+ static void Write##name##_MIO(void *p, u8 off, u8 val) {\
+ struct hws *hw = p;\
+ writeb(val, ((typ *)hw->adr) + off);\
+ } \
+ static void ReadFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ while (size--)\
+ *dp++ = readb(((typ *)hw->adr) + off);\
+ } \
+ static void WriteFiFo##name##_MIO(void *p, u8 off, u8 *dp, int size) {\
+ struct hws *hw = p;\
+ while (size--)\
+ writeb(*dp++, ((typ *)hw->adr) + off);\
+ }
+
+#define ASSIGN_FUNC(typ, name, dest) do {\
+ dest.read_reg = &Read##name##_##typ;\
+ dest.write_reg = &Write##name##_##typ;\
+ dest.read_fifo = &ReadFiFo##name##_##typ;\
+ dest.write_fifo = &WriteFiFo##name##_##typ;\
+ } while (0)
+#define ASSIGN_FUNC_IPAC(typ, target) do {\
+ ASSIGN_FUNC(typ, ISAC, target.isac);\
+ ASSIGN_FUNC(typ, IPAC, target);\
+ } while (0)
+
+#endif
diff --git a/drivers/isdn/hardware/mISDN/ipac.h b/drivers/isdn/hardware/mISDN/ipac.h
new file mode 100644
index 00000000000..74a6ccf9065
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/ipac.h
@@ -0,0 +1,405 @@
+/*
+ *
+ * ipac.h Defines for the Infineon (former Siemens) ISDN
+ * chip series
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "iohelper.h"
+
+struct isac_hw {
+ struct dchannel dch;
+ u32 type;
+ u32 off; /* offset to isac regs */
+ char *name;
+ spinlock_t *hwlock; /* lock HW acccess */
+ read_reg_func *read_reg;
+ write_reg_func *write_reg;
+ fifo_func *read_fifo;
+ fifo_func *write_fifo;
+ int (*monitor)(void *, u32, u8 *, int);
+ void (*release)(struct isac_hw *);
+ int (*init)(struct isac_hw *);
+ int (*ctrl)(struct isac_hw *, u32, u_long);
+ int (*open)(struct isac_hw *, struct channel_req *);
+ u8 *mon_tx;
+ u8 *mon_rx;
+ int mon_txp;
+ int mon_txc;
+ int mon_rxp;
+ struct arcofi_msg *arcofi_list;
+ struct timer_list arcofitimer;
+ wait_queue_head_t arcofi_wait;
+ u8 arcofi_bc;
+ u8 arcofi_state;
+ u8 mocr;
+ u8 adf2;
+ u8 state;
+};
+
+struct ipac_hw;
+
+struct hscx_hw {
+ struct bchannel bch;
+ struct ipac_hw *ip;
+ u8 fifo_size;
+ u8 off; /* offset to ICA or ICB */
+ u8 slot;
+ char log[64];
+};
+
+struct ipac_hw {
+ struct isac_hw isac;
+ struct hscx_hw hscx[2];
+ char *name;
+ void *hw;
+ spinlock_t *hwlock; /* lock HW acccess */
+ struct module *owner;
+ u32 type;
+ read_reg_func *read_reg;
+ write_reg_func *write_reg;
+ fifo_func *read_fifo;
+ fifo_func *write_fifo;
+ void (*release)(struct ipac_hw *);
+ int (*init)(struct ipac_hw *);
+ int (*ctrl)(struct ipac_hw *, u32, u_long);
+ u8 conf;
+};
+
+#define IPAC_TYPE_ISAC 0x0010
+#define IPAC_TYPE_IPAC 0x0020
+#define IPAC_TYPE_ISACX 0x0040
+#define IPAC_TYPE_IPACX 0x0080
+#define IPAC_TYPE_HSCX 0x0100
+
+#define ISAC_USE_ARCOFI 0x1000
+
+/* Monitor functions */
+#define MONITOR_RX_0 0x1000
+#define MONITOR_RX_1 0x1001
+#define MONITOR_TX_0 0x2000
+#define MONITOR_TX_1 0x2001
+
+/* All registers original Siemens Spec */
+/* IPAC/ISAC registers */
+#define ISAC_MASK 0x20
+#define ISAC_ISTA 0x20
+#define ISAC_STAR 0x21
+#define ISAC_CMDR 0x21
+#define ISAC_EXIR 0x24
+#define ISAC_ADF2 0x39
+#define ISAC_SPCR 0x30
+#define ISAC_ADF1 0x38
+#define ISAC_CIR0 0x31
+#define ISAC_CIX0 0x31
+#define ISAC_CIR1 0x33
+#define ISAC_CIX1 0x33
+#define ISAC_STCR 0x37
+#define ISAC_MODE 0x22
+#define ISAC_RSTA 0x27
+#define ISAC_RBCL 0x25
+#define ISAC_RBCH 0x2A
+#define ISAC_TIMR 0x23
+#define ISAC_SQXR 0x3b
+#define ISAC_SQRR 0x3b
+#define ISAC_MOSR 0x3a
+#define ISAC_MOCR 0x3a
+#define ISAC_MOR0 0x32
+#define ISAC_MOX0 0x32
+#define ISAC_MOR1 0x34
+#define ISAC_MOX1 0x34
+
+#define ISAC_RBCH_XAC 0x80
+
+#define IPAC_D_TIN2 0x01
+
+/* IPAC/HSCX */
+#define IPAC_ISTAB 0x20 /* RD */
+#define IPAC_MASKB 0x20 /* WR */
+#define IPAC_STARB 0x21 /* RD */
+#define IPAC_CMDRB 0x21 /* WR */
+#define IPAC_MODEB 0x22 /* R/W */
+#define IPAC_EXIRB 0x24 /* RD */
+#define IPAC_RBCLB 0x25 /* RD */
+#define IPAC_RAH1 0x26 /* WR */
+#define IPAC_RAH2 0x27 /* WR */
+#define IPAC_RSTAB 0x27 /* RD */
+#define IPAC_RAL1 0x28 /* R/W */
+#define IPAC_RAL2 0x29 /* WR */
+#define IPAC_RHCRB 0x29 /* RD */
+#define IPAC_XBCL 0x2A /* WR */
+#define IPAC_CCR2 0x2C /* R/W */
+#define IPAC_RBCHB 0x2D /* RD */
+#define IPAC_XBCH 0x2D /* WR */
+#define HSCX_VSTR 0x2E /* RD */
+#define IPAC_RLCR 0x2E /* WR */
+#define IPAC_CCR1 0x2F /* R/W */
+#define IPAC_TSAX 0x30 /* WR */
+#define IPAC_TSAR 0x31 /* WR */
+#define IPAC_XCCR 0x32 /* WR */
+#define IPAC_RCCR 0x33 /* WR */
+
+/* IPAC_ISTAB/IPAC_MASKB bits */
+#define IPAC_B_XPR 0x10
+#define IPAC_B_RPF 0x40
+#define IPAC_B_RME 0x80
+#define IPAC_B_ON 0x2F
+
+/* IPAC_EXIRB bits */
+#define IPAC_B_RFS 0x04
+#define IPAC_B_RFO 0x10
+#define IPAC_B_XDU 0x40
+#define IPAC_B_XMR 0x80
+
+/* IPAC special registers */
+#define IPAC_CONF 0xC0 /* R/W */
+#define IPAC_ISTA 0xC1 /* RD */
+#define IPAC_MASK 0xC1 /* WR */
+#define IPAC_ID 0xC2 /* RD */
+#define IPAC_ACFG 0xC3 /* R/W */
+#define IPAC_AOE 0xC4 /* R/W */
+#define IPAC_ARX 0xC5 /* RD */
+#define IPAC_ATX 0xC5 /* WR */
+#define IPAC_PITA1 0xC6 /* R/W */
+#define IPAC_PITA2 0xC7 /* R/W */
+#define IPAC_POTA1 0xC8 /* R/W */
+#define IPAC_POTA2 0xC9 /* R/W */
+#define IPAC_PCFG 0xCA /* R/W */
+#define IPAC_SCFG 0xCB /* R/W */
+#define IPAC_TIMR2 0xCC /* R/W */
+
+/* IPAC_ISTA/_MASK bits */
+#define IPAC__EXB 0x01
+#define IPAC__ICB 0x02
+#define IPAC__EXA 0x04
+#define IPAC__ICA 0x08
+#define IPAC__EXD 0x10
+#define IPAC__ICD 0x20
+#define IPAC__INT0 0x40
+#define IPAC__INT1 0x80
+#define IPAC__ON 0xC0
+
+/* HSCX ISTA/MASK bits */
+#define HSCX__EXB 0x01
+#define HSCX__EXA 0x02
+#define HSCX__ICA 0x04
+
+/* ISAC/ISACX/IPAC/IPACX L1 commands */
+#define ISAC_CMD_TIM 0x0
+#define ISAC_CMD_RS 0x1
+#define ISAC_CMD_SCZ 0x4
+#define ISAC_CMD_SSZ 0x2
+#define ISAC_CMD_AR8 0x8
+#define ISAC_CMD_AR10 0x9
+#define ISAC_CMD_ARL 0xA
+#define ISAC_CMD_DUI 0xF
+
+/* ISAC/ISACX/IPAC/IPACX L1 indications */
+#define ISAC_IND_RS 0x1
+#define ISAC_IND_PU 0x7
+#define ISAC_IND_DR 0x0
+#define ISAC_IND_SD 0x2
+#define ISAC_IND_DIS 0x3
+#define ISAC_IND_EI 0x6
+#define ISAC_IND_RSY 0x4
+#define ISAC_IND_ARD 0x8
+#define ISAC_IND_TI 0xA
+#define ISAC_IND_ATI 0xB
+#define ISAC_IND_AI8 0xC
+#define ISAC_IND_AI10 0xD
+#define ISAC_IND_DID 0xF
+
+/* the new ISACX / IPACX */
+/* D-channel registers */
+#define ISACX_RFIFOD 0x00 /* RD */
+#define ISACX_XFIFOD 0x00 /* WR */
+#define ISACX_ISTAD 0x20 /* RD */
+#define ISACX_MASKD 0x20 /* WR */
+#define ISACX_STARD 0x21 /* RD */
+#define ISACX_CMDRD 0x21 /* WR */
+#define ISACX_MODED 0x22 /* R/W */
+#define ISACX_EXMD1 0x23 /* R/W */
+#define ISACX_TIMR1 0x24 /* R/W */
+#define ISACX_SAP1 0x25 /* WR */
+#define ISACX_SAP2 0x26 /* WR */
+#define ISACX_RBCLD 0x26 /* RD */
+#define ISACX_RBCHD 0x27 /* RD */
+#define ISACX_TEI1 0x27 /* WR */
+#define ISACX_TEI2 0x28 /* WR */
+#define ISACX_RSTAD 0x28 /* RD */
+#define ISACX_TMD 0x29 /* R/W */
+#define ISACX_CIR0 0x2E /* RD */
+#define ISACX_CIX0 0x2E /* WR */
+#define ISACX_CIR1 0x2F /* RD */
+#define ISACX_CIX1 0x2F /* WR */
+
+/* Transceiver registers */
+#define ISACX_TR_CONF0 0x30 /* R/W */
+#define ISACX_TR_CONF1 0x31 /* R/W */
+#define ISACX_TR_CONF2 0x32 /* R/W */
+#define ISACX_TR_STA 0x33 /* RD */
+#define ISACX_TR_CMD 0x34 /* R/W */
+#define ISACX_SQRR1 0x35 /* RD */
+#define ISACX_SQXR1 0x35 /* WR */
+#define ISACX_SQRR2 0x36 /* RD */
+#define ISACX_SQXR2 0x36 /* WR */
+#define ISACX_SQRR3 0x37 /* RD */
+#define ISACX_SQXR3 0x37 /* WR */
+#define ISACX_ISTATR 0x38 /* RD */
+#define ISACX_MASKTR 0x39 /* R/W */
+#define ISACX_TR_MODE 0x3A /* R/W */
+#define ISACX_ACFG1 0x3C /* R/W */
+#define ISACX_ACFG2 0x3D /* R/W */
+#define ISACX_AOE 0x3E /* R/W */
+#define ISACX_ARX 0x3F /* RD */
+#define ISACX_ATX 0x3F /* WR */
+
+/* IOM: Timeslot, DPS, CDA */
+#define ISACX_CDA10 0x40 /* R/W */
+#define ISACX_CDA11 0x41 /* R/W */
+#define ISACX_CDA20 0x42 /* R/W */
+#define ISACX_CDA21 0x43 /* R/W */
+#define ISACX_CDA_TSDP10 0x44 /* R/W */
+#define ISACX_CDA_TSDP11 0x45 /* R/W */
+#define ISACX_CDA_TSDP20 0x46 /* R/W */
+#define ISACX_CDA_TSDP21 0x47 /* R/W */
+#define ISACX_BCHA_TSDP_BC1 0x48 /* R/W */
+#define ISACX_BCHA_TSDP_BC2 0x49 /* R/W */
+#define ISACX_BCHB_TSDP_BC1 0x4A /* R/W */
+#define ISACX_BCHB_TSDP_BC2 0x4B /* R/W */
+#define ISACX_TR_TSDP_BC1 0x4C /* R/W */
+#define ISACX_TR_TSDP_BC2 0x4D /* R/W */
+#define ISACX_CDA1_CR 0x4E /* R/W */
+#define ISACX_CDA2_CR 0x4F /* R/W */
+
+/* IOM: Contol, Sync transfer, Monitor */
+#define ISACX_TR_CR 0x50 /* R/W */
+#define ISACX_TRC_CR 0x50 /* R/W */
+#define ISACX_BCHA_CR 0x51 /* R/W */
+#define ISACX_BCHB_CR 0x52 /* R/W */
+#define ISACX_DCI_CR 0x53 /* R/W */
+#define ISACX_DCIC_CR 0x53 /* R/W */
+#define ISACX_MON_CR 0x54 /* R/W */
+#define ISACX_SDS1_CR 0x55 /* R/W */
+#define ISACX_SDS2_CR 0x56 /* R/W */
+#define ISACX_IOM_CR 0x57 /* R/W */
+#define ISACX_STI 0x58 /* RD */
+#define ISACX_ASTI 0x58 /* WR */
+#define ISACX_MSTI 0x59 /* R/W */
+#define ISACX_SDS_CONF 0x5A /* R/W */
+#define ISACX_MCDA 0x5B /* RD */
+#define ISACX_MOR 0x5C /* RD */
+#define ISACX_MOX 0x5C /* WR */
+#define ISACX_MOSR 0x5D /* RD */
+#define ISACX_MOCR 0x5E /* R/W */
+#define ISACX_MSTA 0x5F /* RD */
+#define ISACX_MCONF 0x5F /* WR */
+
+/* Interrupt and general registers */
+#define ISACX_ISTA 0x60 /* RD */
+#define ISACX_MASK 0x60 /* WR */
+#define ISACX_AUXI 0x61 /* RD */
+#define ISACX_AUXM 0x61 /* WR */
+#define ISACX_MODE1 0x62 /* R/W */
+#define ISACX_MODE2 0x63 /* R/W */
+#define ISACX_ID 0x64 /* RD */
+#define ISACX_SRES 0x64 /* WR */
+#define ISACX_TIMR2 0x65 /* R/W */
+
+/* Register Bits */
+/* ISACX/IPACX _ISTAD (R) and _MASKD (W) */
+#define ISACX_D_XDU 0x04
+#define ISACX_D_XMR 0x08
+#define ISACX_D_XPR 0x10
+#define ISACX_D_RFO 0x20
+#define ISACX_D_RPF 0x40
+#define ISACX_D_RME 0x80
+
+/* ISACX/IPACX _ISTA (R) and _MASK (W) */
+#define ISACX__ICD 0x01
+#define ISACX__MOS 0x02
+#define ISACX__TRAN 0x04
+#define ISACX__AUX 0x08
+#define ISACX__CIC 0x10
+#define ISACX__ST 0x20
+#define IPACX__ICB 0x40
+#define IPACX__ICA 0x80
+#define IPACX__ON 0x2C
+
+/* ISACX/IPACX _CMDRD (W) */
+#define ISACX_CMDRD_XRES 0x01
+#define ISACX_CMDRD_XME 0x02
+#define ISACX_CMDRD_XTF 0x08
+#define ISACX_CMDRD_STI 0x10
+#define ISACX_CMDRD_RRES 0x40
+#define ISACX_CMDRD_RMC 0x80
+
+/* ISACX/IPACX _RSTAD (R) */
+#define ISACX_RSTAD_TA 0x01
+#define ISACX_RSTAD_CR 0x02
+#define ISACX_RSTAD_SA0 0x04
+#define ISACX_RSTAD_SA1 0x08
+#define ISACX_RSTAD_RAB 0x10
+#define ISACX_RSTAD_CRC 0x20
+#define ISACX_RSTAD_RDO 0x40
+#define ISACX_RSTAD_VFR 0x80
+
+/* ISACX/IPACX _CIR0 (R) */
+#define ISACX_CIR0_BAS 0x01
+#define ISACX_CIR0_SG 0x08
+#define ISACX_CIR0_CIC1 0x08
+#define ISACX_CIR0_CIC0 0x08
+
+/* B-channel registers */
+#define IPACX_OFF_ICA 0x70
+#define IPACX_OFF_ICB 0x80
+
+/* ICA: IPACX_OFF_ICA + Reg ICB: IPACX_OFF_ICB + Reg */
+
+#define IPACX_ISTAB 0x00 /* RD */
+#define IPACX_MASKB 0x00 /* WR */
+#define IPACX_STARB 0x01 /* RD */
+#define IPACX_CMDRB 0x01 /* WR */
+#define IPACX_MODEB 0x02 /* R/W */
+#define IPACX_EXMB 0x03 /* R/W */
+#define IPACX_RAH1 0x05 /* WR */
+#define IPACX_RAH2 0x06 /* WR */
+#define IPACX_RBCLB 0x06 /* RD */
+#define IPACX_RBCHB 0x07 /* RD */
+#define IPACX_RAL1 0x07 /* WR */
+#define IPACX_RAL2 0x08 /* WR */
+#define IPACX_RSTAB 0x08 /* RD */
+#define IPACX_TMB 0x09 /* R/W */
+#define IPACX_RFIFOB 0x0A /* RD */
+#define IPACX_XFIFOB 0x0A /* WR */
+
+/* IPACX_ISTAB / IPACX_MASKB bits */
+#define IPACX_B_XDU 0x04
+#define IPACX_B_XPR 0x10
+#define IPACX_B_RFO 0x20
+#define IPACX_B_RPF 0x40
+#define IPACX_B_RME 0x80
+
+#define IPACX_B_ON 0x0B
+
+extern int mISDNisac_init(struct isac_hw *, void *);
+extern irqreturn_t mISDNisac_irq(struct isac_hw *, u8);
+extern u32 mISDNipac_init(struct ipac_hw *, void *);
+extern irqreturn_t mISDNipac_irq(struct ipac_hw *, int);
diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h
new file mode 100644
index 00000000000..4a134acd44d
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/isar.h
@@ -0,0 +1,269 @@
+/*
+ *
+ * isar.h ISAR (Siemens PSB 7110) specific defines
+ *
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "iohelper.h"
+
+struct isar_hw;
+
+struct isar_ch {
+ struct bchannel bch;
+ struct isar_hw *is;
+ struct timer_list ftimer;
+ u8 nr;
+ u8 dpath;
+ u8 mml;
+ u8 state;
+ u8 cmd;
+ u8 mod;
+ u8 newcmd;
+ u8 newmod;
+ u8 try_mod;
+ u8 conmsg[16];
+};
+
+struct isar_hw {
+ struct isar_ch ch[2];
+ void *hw;
+ spinlock_t *hwlock; /* lock HW acccess */
+ char *name;
+ struct module *owner;
+ read_reg_func *read_reg;
+ write_reg_func *write_reg;
+ fifo_func *read_fifo;
+ fifo_func *write_fifo;
+ int (*ctrl)(void *, u32, u_long);
+ void (*release)(struct isar_hw *);
+ int (*init)(struct isar_hw *);
+ int (*open)(struct isar_hw *, struct channel_req *);
+ int (*firmware)(struct isar_hw *, const u8 *, int);
+ unsigned long Flags;
+ int version;
+ u8 bstat;
+ u8 iis;
+ u8 cmsb;
+ u8 clsb;
+ u8 buf[256];
+ u8 log[256];
+};
+
+#define ISAR_IRQMSK 0x04
+#define ISAR_IRQSTA 0x04
+#define ISAR_IRQBIT 0x75
+#define ISAR_CTRL_H 0x61
+#define ISAR_CTRL_L 0x60
+#define ISAR_IIS 0x58
+#define ISAR_IIA 0x58
+#define ISAR_HIS 0x50
+#define ISAR_HIA 0x50
+#define ISAR_MBOX 0x4c
+#define ISAR_WADR 0x4a
+#define ISAR_RADR 0x48
+
+#define ISAR_HIS_VNR 0x14
+#define ISAR_HIS_DKEY 0x02
+#define ISAR_HIS_FIRM 0x1e
+#define ISAR_HIS_STDSP 0x08
+#define ISAR_HIS_DIAG 0x05
+#define ISAR_HIS_P0CFG 0x3c
+#define ISAR_HIS_P12CFG 0x24
+#define ISAR_HIS_SARTCFG 0x25
+#define ISAR_HIS_PUMPCFG 0x26
+#define ISAR_HIS_PUMPCTRL 0x2a
+#define ISAR_HIS_IOM2CFG 0x27
+#define ISAR_HIS_IOM2REQ 0x07
+#define ISAR_HIS_IOM2CTRL 0x2b
+#define ISAR_HIS_BSTREQ 0x0c
+#define ISAR_HIS_PSTREQ 0x0e
+#define ISAR_HIS_SDATA 0x20
+#define ISAR_HIS_DPS1 0x40
+#define ISAR_HIS_DPS2 0x80
+#define SET_DPS(x) ((x<<6) & 0xc0)
+
+#define ISAR_IIS_MSCMSD 0x3f
+#define ISAR_IIS_VNR 0x15
+#define ISAR_IIS_DKEY 0x03
+#define ISAR_IIS_FIRM 0x1f
+#define ISAR_IIS_STDSP 0x09
+#define ISAR_IIS_DIAG 0x25
+#define ISAR_IIS_GSTEV 0x00
+#define ISAR_IIS_BSTEV 0x28
+#define ISAR_IIS_BSTRSP 0x2c
+#define ISAR_IIS_PSTRSP 0x2e
+#define ISAR_IIS_PSTEV 0x2a
+#define ISAR_IIS_IOM2RSP 0x27
+#define ISAR_IIS_RDATA 0x20
+#define ISAR_IIS_INVMSG 0x3f
+
+#define ISAR_CTRL_SWVER 0x10
+#define ISAR_CTRL_STST 0x40
+
+#define ISAR_MSG_HWVER 0x20
+
+#define ISAR_DP1_USE 1
+#define ISAR_DP2_USE 2
+#define ISAR_RATE_REQ 3
+
+#define PMOD_DISABLE 0
+#define PMOD_FAX 1
+#define PMOD_DATAMODEM 2
+#define PMOD_HALFDUPLEX 3
+#define PMOD_V110 4
+#define PMOD_DTMF 5
+#define PMOD_DTMF_TRANS 6
+#define PMOD_BYPASS 7
+
+#define PCTRL_ORIG 0x80
+#define PV32P2_V23R 0x40
+#define PV32P2_V22A 0x20
+#define PV32P2_V22B 0x10
+#define PV32P2_V22C 0x08
+#define PV32P2_V21 0x02
+#define PV32P2_BEL 0x01
+
+/* LSB MSB in ISAR doc wrong !!! Arghhh */
+#define PV32P3_AMOD 0x80
+#define PV32P3_V32B 0x02
+#define PV32P3_V23B 0x01
+#define PV32P4_48 0x11
+#define PV32P5_48 0x05
+#define PV32P4_UT48 0x11
+#define PV32P5_UT48 0x0d
+#define PV32P4_96 0x11
+#define PV32P5_96 0x03
+#define PV32P4_UT96 0x11
+#define PV32P5_UT96 0x0f
+#define PV32P4_B96 0x91
+#define PV32P5_B96 0x0b
+#define PV32P4_UTB96 0xd1
+#define PV32P5_UTB96 0x0f
+#define PV32P4_120 0xb1
+#define PV32P5_120 0x09
+#define PV32P4_UT120 0xf1
+#define PV32P5_UT120 0x0f
+#define PV32P4_144 0x99
+#define PV32P5_144 0x09
+#define PV32P4_UT144 0xf9
+#define PV32P5_UT144 0x0f
+#define PV32P6_CTN 0x01
+#define PV32P6_ATN 0x02
+
+#define PFAXP2_CTN 0x01
+#define PFAXP2_ATN 0x04
+
+#define PSEV_10MS_TIMER 0x02
+#define PSEV_CON_ON 0x18
+#define PSEV_CON_OFF 0x19
+#define PSEV_V24_OFF 0x20
+#define PSEV_CTS_ON 0x21
+#define PSEV_CTS_OFF 0x22
+#define PSEV_DCD_ON 0x23
+#define PSEV_DCD_OFF 0x24
+#define PSEV_DSR_ON 0x25
+#define PSEV_DSR_OFF 0x26
+#define PSEV_REM_RET 0xcc
+#define PSEV_REM_REN 0xcd
+#define PSEV_GSTN_CLR 0xd4
+
+#define PSEV_RSP_READY 0xbc
+#define PSEV_LINE_TX_H 0xb3
+#define PSEV_LINE_TX_B 0xb2
+#define PSEV_LINE_RX_H 0xb1
+#define PSEV_LINE_RX_B 0xb0
+#define PSEV_RSP_CONN 0xb5
+#define PSEV_RSP_DISC 0xb7
+#define PSEV_RSP_FCERR 0xb9
+#define PSEV_RSP_SILDET 0xbe
+#define PSEV_RSP_SILOFF 0xab
+#define PSEV_FLAGS_DET 0xba
+
+#define PCTRL_CMD_TDTMF 0x5a
+
+#define PCTRL_CMD_FTH 0xa7
+#define PCTRL_CMD_FRH 0xa5
+#define PCTRL_CMD_FTM 0xa8
+#define PCTRL_CMD_FRM 0xa6
+#define PCTRL_CMD_SILON 0xac
+#define PCTRL_CMD_CONT 0xa2
+#define PCTRL_CMD_ESC 0xa4
+#define PCTRL_CMD_SILOFF 0xab
+#define PCTRL_CMD_HALT 0xa9
+
+#define PCTRL_LOC_RET 0xcf
+#define PCTRL_LOC_REN 0xce
+
+#define SMODE_DISABLE 0
+#define SMODE_V14 2
+#define SMODE_HDLC 3
+#define SMODE_BINARY 4
+#define SMODE_FSK_V14 5
+
+#define SCTRL_HDMC_BOTH 0x00
+#define SCTRL_HDMC_DTX 0x80
+#define SCTRL_HDMC_DRX 0x40
+#define S_P1_OVSP 0x40
+#define S_P1_SNP 0x20
+#define S_P1_EOP 0x10
+#define S_P1_EDP 0x08
+#define S_P1_NSB 0x04
+#define S_P1_CHS_8 0x03
+#define S_P1_CHS_7 0x02
+#define S_P1_CHS_6 0x01
+#define S_P1_CHS_5 0x00
+
+#define S_P2_BFT_DEF 0x10
+
+#define IOM_CTRL_ENA 0x80
+#define IOM_CTRL_NOPCM 0x00
+#define IOM_CTRL_ALAW 0x02
+#define IOM_CTRL_ULAW 0x04
+#define IOM_CTRL_RCV 0x01
+
+#define IOM_P1_TXD 0x10
+
+#define HDLC_FED 0x40
+#define HDLC_FSD 0x20
+#define HDLC_FST 0x20
+#define HDLC_ERROR 0x1c
+#define HDLC_ERR_FAD 0x10
+#define HDLC_ERR_RER 0x08
+#define HDLC_ERR_CER 0x04
+#define SART_NMD 0x01
+
+#define BSTAT_RDM0 0x1
+#define BSTAT_RDM1 0x2
+#define BSTAT_RDM2 0x4
+#define BSTAT_RDM3 0x8
+#define BSTEV_TBO 0x1f
+#define BSTEV_RBO 0x2f
+
+/* FAX State Machine */
+#define STFAX_NULL 0
+#define STFAX_READY 1
+#define STFAX_LINE 2
+#define STFAX_CONT 3
+#define STFAX_ACTIV 4
+#define STFAX_ESCAPE 5
+#define STFAX_SILDET 6
+
+extern u32 mISDNisar_init(struct isar_hw *, void *);
+extern void mISDNisar_irq(struct isar_hw *);
diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
new file mode 100644
index 00000000000..62441ba53b9
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c
@@ -0,0 +1,1178 @@
+/*
+ * mISDNinfineon.c
+ * Support for cards based on following Infineon ISDN chipsets
+ * - ISAC + HSCX
+ * - IPAC and IPAC-X
+ * - ISAC-SX + HSCX
+ *
+ * Supported cards:
+ * - Dialogic Diva 2.0
+ * - Dialogic Diva 2.0U
+ * - Dialogic Diva 2.01
+ * - Dialogic Diva 2.02
+ * - Sedlbauer Speedwin
+ * - HST Saphir3
+ * - Develo (former ELSA) Microlink PCI (Quickstep 1000)
+ * - Develo (former ELSA) Quickstep 3000
+ * - Berkom Scitel BRIX Quadro
+ * - Dr.Neuhaus (Sagem) Niccy
+ *
+ *
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "ipac.h"
+
+#define INFINEON_REV "1.0"
+
+static int inf_cnt;
+static u32 debug;
+static u32 irqloops = 4;
+
+enum inf_types {
+ INF_NONE,
+ INF_DIVA20,
+ INF_DIVA20U,
+ INF_DIVA201,
+ INF_DIVA202,
+ INF_SPEEDWIN,
+ INF_SAPHIR3,
+ INF_QS1000,
+ INF_QS3000,
+ INF_NICCY,
+ INF_SCT_1,
+ INF_SCT_2,
+ INF_SCT_3,
+ INF_SCT_4,
+ INF_GAZEL_R685,
+ INF_GAZEL_R753
+};
+
+enum addr_mode {
+ AM_NONE = 0,
+ AM_IO,
+ AM_MEMIO,
+ AM_IND_IO,
+};
+
+struct inf_cinfo {
+ enum inf_types typ;
+ const char *full;
+ const char *name;
+ enum addr_mode cfg_mode;
+ enum addr_mode addr_mode;
+ u8 cfg_bar;
+ u8 addr_bar;
+ void *irqfunc;
+};
+
+struct _ioaddr {
+ enum addr_mode mode;
+ union {
+ void __iomem *p;
+ struct _ioport io;
+ } a;
+};
+
+struct _iohandle {
+ enum addr_mode mode;
+ resource_size_t size;
+ resource_size_t start;
+ void __iomem *p;
+};
+
+struct inf_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ const struct inf_cinfo *ci;
+ char name[MISDN_MAX_IDLEN];
+ u32 irq;
+ u32 irqcnt;
+ struct _iohandle cfg;
+ struct _iohandle addr;
+ struct _ioaddr isac;
+ struct _ioaddr hscx;
+ spinlock_t lock; /* HW access lock */
+ struct ipac_hw ipac;
+ struct inf_hw *sc[3]; /* slave cards */
+};
+
+
+#define PCI_SUBVENDOR_HST_SAPHIR3 0x52
+#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
+#define PCI_SUB_ID_SEDLBAUER 0x01
+
+static struct pci_device_id infineon_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA20U},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA201},
+ { PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_DIVA202},
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_SEDLBAUER_PCI, PCI_SUB_ID_SEDLBAUER, 0, 0,
+ INF_SPEEDWIN},
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_HST_SAPHIR3, PCI_SUB_ID_SEDLBAUER, 0, 0, INF_SAPHIR3},
+ { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS1000},
+ { PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_QS3000,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_QS3000},
+ { PCI_VENDOR_ID_SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_NICCY},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+ PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO, 0, 0,
+ INF_SCT_1},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R685,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R685},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_R753,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_OLITEC,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, INF_GAZEL_R753},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, infineon_ids);
+
+/* PCI interface specific defines */
+/* Diva 2.0/2.0U */
+#define DIVA_HSCX_PORT 0x00
+#define DIVA_HSCX_ALE 0x04
+#define DIVA_ISAC_PORT 0x08
+#define DIVA_ISAC_ALE 0x0C
+#define DIVA_PCI_CTRL 0x10
+
+/* DIVA_PCI_CTRL bits */
+#define DIVA_IRQ_BIT 0x01
+#define DIVA_RESET_BIT 0x08
+#define DIVA_EEPROM_CLK 0x40
+#define DIVA_LED_A 0x10
+#define DIVA_LED_B 0x20
+#define DIVA_IRQ_CLR 0x80
+
+/* Diva 2.01/2.02 */
+/* Siemens PITA */
+#define PITA_ICR_REG 0x00
+#define PITA_INT0_STATUS 0x02
+
+#define PITA_MISC_REG 0x1c
+#define PITA_PARA_SOFTRESET 0x01000000
+#define PITA_SER_SOFTRESET 0x02000000
+#define PITA_PARA_MPX_MODE 0x04000000
+#define PITA_INT0_ENABLE 0x00020000
+
+/* TIGER 100 Registers */
+#define TIGER_RESET_ADDR 0x00
+#define TIGER_EXTERN_RESET 0x01
+#define TIGER_AUX_CTRL 0x02
+#define TIGER_AUX_DATA 0x03
+#define TIGER_AUX_IRQMASK 0x05
+#define TIGER_AUX_STATUS 0x07
+
+/* Tiger AUX BITs */
+#define TIGER_IOMASK 0xdd /* 1 and 5 are inputs */
+#define TIGER_IRQ_BIT 0x02
+
+#define TIGER_IPAC_ALE 0xC0
+#define TIGER_IPAC_PORT 0xC8
+
+/* ELSA (now Develo) PCI cards */
+#define ELSA_IRQ_ADDR 0x4c
+#define ELSA_IRQ_MASK 0x04
+#define QS1000_IRQ_OFF 0x01
+#define QS3000_IRQ_OFF 0x03
+#define QS1000_IRQ_ON 0x41
+#define QS3000_IRQ_ON 0x43
+
+/* Dr Neuhaus/Sagem Niccy */
+#define NICCY_ISAC_PORT 0x00
+#define NICCY_HSCX_PORT 0x01
+#define NICCY_ISAC_ALE 0x02
+#define NICCY_HSCX_ALE 0x03
+
+#define NICCY_IRQ_CTRL_REG 0x38
+#define NICCY_IRQ_ENABLE 0x001f00
+#define NICCY_IRQ_DISABLE 0xff0000
+#define NICCY_IRQ_BIT 0x800000
+
+
+/* Scitel PLX */
+#define SCT_PLX_IRQ_ADDR 0x4c
+#define SCT_PLX_RESET_ADDR 0x50
+#define SCT_PLX_IRQ_ENABLE 0x41
+#define SCT_PLX_RESET_BIT 0x04
+
+/* Gazel */
+#define GAZEL_IPAC_DATA_PORT 0x04
+/* Gazel PLX */
+#define GAZEL_CNTRL 0x50
+#define GAZEL_RESET 0x04
+#define GAZEL_RESET_9050 0x40000000
+#define GAZEL_INCSR 0x4C
+#define GAZEL_ISAC_EN 0x08
+#define GAZEL_INT_ISAC 0x20
+#define GAZEL_HSCX_EN 0x01
+#define GAZEL_INT_HSCX 0x04
+#define GAZEL_PCI_EN 0x40
+#define GAZEL_IPAC_EN 0x03
+
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static void
+_set_debug(struct inf_hw *card)
+{
+ card->ipac.isac.dch.debug = debug;
+ card->ipac.hscx[0].bch.debug = debug;
+ card->ipac.hscx[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct inf_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(INFINEON_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "infineon debug mask");
+module_param(irqloops, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(irqloops, "infineon maximal irqloops (default 4)");
+
+/* Interface functions */
+
+IOFUNC_IO(ISAC, inf_hw, isac.a.io)
+IOFUNC_IO(IPAC, inf_hw, hscx.a.io)
+IOFUNC_IND(ISAC, inf_hw, isac.a.io)
+IOFUNC_IND(IPAC, inf_hw, hscx.a.io)
+IOFUNC_MEMIO(ISAC, inf_hw, u32, isac.a.p)
+IOFUNC_MEMIO(IPAC, inf_hw, u32, hscx.a.p)
+
+static irqreturn_t
+diva_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + DIVA_PCI_CTRL);
+ if (!(val & DIVA_IRQ_BIT)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+diva20x_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = readb(hw->cfg.p);
+ if (!(val & PITA_INT0_STATUS)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ writeb(PITA_INT0_STATUS, hw->cfg.p); /* ACK PITA INT0 */
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+tiger_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + TIGER_AUX_STATUS);
+ if (val & TIGER_IRQ_BIT) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+elsa_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = inb((u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ if (!(val & ELSA_IRQ_MASK)) {
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+niccy_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u32 val;
+
+ spin_lock(&hw->lock);
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ if (!(val & NICCY_IRQ_BIT)) { /* for us or shared ? */
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+gazel_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ irqreturn_t ret;
+
+ spin_lock(&hw->lock);
+ ret = mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return ret;
+}
+
+static irqreturn_t
+ipac_irq(int intno, void *dev_id)
+{
+ struct inf_hw *hw = dev_id;
+ u8 val;
+
+ spin_lock(&hw->lock);
+ val = hw->ipac.read_reg(hw, IPAC_ISTA);
+ if (!(val & 0x3f)) {
+ spin_unlock(&hw->lock);
+ return IRQ_NONE; /* shared */
+ }
+ hw->irqcnt++;
+ mISDNipac_irq(&hw->ipac, irqloops);
+ spin_unlock(&hw->lock);
+ return IRQ_HANDLED;
+}
+
+static void
+enable_hwirq(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ switch (hw->ci->typ) {
+ case INF_DIVA201:
+ case INF_DIVA202:
+ writel(PITA_INT0_ENABLE, hw->cfg.p);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ outb(TIGER_IRQ_BIT, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
+ break;
+ case INF_QS1000:
+ outb(QS1000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_QS3000:
+ outb(QS3000_IRQ_ON, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_NICCY:
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ val |= NICCY_IRQ_ENABLE;;
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ w |= SCT_PLX_IRQ_ENABLE;
+ outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ break;
+ case INF_GAZEL_R685:
+ outb(GAZEL_ISAC_EN + GAZEL_HSCX_EN + GAZEL_PCI_EN,
+ (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ case INF_GAZEL_R753:
+ outb(GAZEL_IPAC_EN + GAZEL_PCI_EN,
+ (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+disable_hwirq(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ switch (hw->ci->typ) {
+ case INF_DIVA201:
+ case INF_DIVA202:
+ writel(0, hw->cfg.p);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ outb(0, (u32)hw->cfg.start + TIGER_AUX_IRQMASK);
+ break;
+ case INF_QS1000:
+ outb(QS1000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_QS3000:
+ outb(QS3000_IRQ_OFF, (u32)hw->cfg.start + ELSA_IRQ_ADDR);
+ break;
+ case INF_NICCY:
+ val = inl((u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ val &= NICCY_IRQ_DISABLE;
+ outl(val, (u32)hw->cfg.start + NICCY_IRQ_CTRL_REG);
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ w &= (~SCT_PLX_IRQ_ENABLE);
+ outw(w, (u32)hw->cfg.start + SCT_PLX_IRQ_ADDR);
+ break;
+ case INF_GAZEL_R685:
+ case INF_GAZEL_R753:
+ outb(0, (u32)hw->cfg.start + GAZEL_INCSR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+ipac_chip_reset(struct inf_hw *hw)
+{
+ hw->ipac.write_reg(hw, IPAC_POTA2, 0x20);
+ mdelay(5);
+ hw->ipac.write_reg(hw, IPAC_POTA2, 0x00);
+ mdelay(5);
+ hw->ipac.write_reg(hw, IPAC_CONF, hw->ipac.conf);
+ hw->ipac.write_reg(hw, IPAC_MASK, 0xc0);
+}
+
+static void
+reset_inf(struct inf_hw *hw)
+{
+ u16 w;
+ u32 val;
+
+ if (debug & DEBUG_HW)
+ pr_notice("%s: resetting card\n", hw->name);
+ switch (hw->ci->typ) {
+ case INF_DIVA20:
+ case INF_DIVA20U:
+ outb(0, (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ mdelay(10);
+ outb(DIVA_RESET_BIT, (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ mdelay(10);
+ /* Workaround PCI9060 */
+ outb(9, (u32)hw->cfg.start + 0x69);
+ outb(DIVA_RESET_BIT | DIVA_LED_A,
+ (u32)hw->cfg.start + DIVA_PCI_CTRL);
+ break;
+ case INF_DIVA201:
+ writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(1);
+ writel(PITA_PARA_MPX_MODE, hw->cfg.p + PITA_MISC_REG);
+ mdelay(10);
+ break;
+ case INF_DIVA202:
+ writel(PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(1);
+ writel(PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET,
+ hw->cfg.p + PITA_MISC_REG);
+ mdelay(10);
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ ipac_chip_reset(hw);
+ hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
+ hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
+ hw->ipac.write_reg(hw, IPAC_PCFG, 0x12);
+ break;
+ case INF_QS1000:
+ case INF_QS3000:
+ ipac_chip_reset(hw);
+ hw->ipac.write_reg(hw, IPAC_ACFG, 0x00);
+ hw->ipac.write_reg(hw, IPAC_AOE, 0x3c);
+ hw->ipac.write_reg(hw, IPAC_ATX, 0xff);
+ break;
+ case INF_NICCY:
+ break;
+ case INF_SCT_1:
+ w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
+ w &= (~SCT_PLX_RESET_BIT);
+ outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
+ mdelay(10);
+ w = inw((u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
+ w |= SCT_PLX_RESET_BIT;
+ outw(w, (u32)hw->cfg.start + SCT_PLX_RESET_ADDR);
+ mdelay(10);
+ break;
+ case INF_GAZEL_R685:
+ val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
+ val |= (GAZEL_RESET_9050 + GAZEL_RESET);
+ outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
+ val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);
+ mdelay(4);
+ outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
+ mdelay(10);
+ hw->ipac.isac.adf2 = 0x87;
+ hw->ipac.hscx[0].slot = 0x1f;
+ hw->ipac.hscx[0].slot = 0x23;
+ break;
+ case INF_GAZEL_R753:
+ val = inl((u32)hw->cfg.start + GAZEL_CNTRL);
+ val |= (GAZEL_RESET_9050 + GAZEL_RESET);
+ outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
+ val &= ~(GAZEL_RESET_9050 + GAZEL_RESET);
+ mdelay(4);
+ outl(val, (u32)hw->cfg.start + GAZEL_CNTRL);
+ mdelay(10);
+ ipac_chip_reset(hw);
+ hw->ipac.write_reg(hw, IPAC_ACFG, 0xff);
+ hw->ipac.write_reg(hw, IPAC_AOE, 0x00);
+ hw->ipac.conf = 0x01; /* IOM off */
+ break;
+ default:
+ return;
+ }
+ enable_hwirq(hw);
+}
+
+static int
+inf_ctrl(struct inf_hw *hw, u32 cmd, u_long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case HW_RESET_REQ:
+ reset_inf(hw);
+ break;
+ default:
+ pr_info("%s: %s unknown command %x %lx\n",
+ hw->name, __func__, cmd, arg);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int __devinit
+init_irq(struct inf_hw *hw)
+{
+ int ret, cnt = 3;
+ u_long flags;
+
+ if (!hw->ci->irqfunc)
+ return -EINVAL;
+ ret = request_irq(hw->irq, hw->ci->irqfunc, IRQF_SHARED, hw->name, hw);
+ if (ret) {
+ pr_info("%s: couldn't get interrupt %d\n", hw->name, hw->irq);
+ return ret;
+ }
+ while (cnt--) {
+ spin_lock_irqsave(&hw->lock, flags);
+ reset_inf(hw);
+ ret = hw->ipac.init(&hw->ipac);
+ if (ret) {
+ spin_unlock_irqrestore(&hw->lock, flags);
+ pr_info("%s: ISAC init failed with %d\n",
+ hw->name, ret);
+ break;
+ }
+ spin_unlock_irqrestore(&hw->lock, flags);
+ msleep_interruptible(10);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IRQ %d count %d\n", hw->name,
+ hw->irq, hw->irqcnt);
+ if (!hw->irqcnt) {
+ pr_info("%s: IRQ(%d) got no requests during init %d\n",
+ hw->name, hw->irq, 3 - cnt);
+ } else
+ return 0;
+ }
+ free_irq(hw->irq, hw);
+ return -EIO;
+}
+
+static void
+release_io(struct inf_hw *hw)
+{
+ if (hw->cfg.mode) {
+ if (hw->cfg.p) {
+ release_mem_region(hw->cfg.start, hw->cfg.size);
+ iounmap(hw->cfg.p);
+ } else
+ release_region(hw->cfg.start, hw->cfg.size);
+ hw->cfg.mode = AM_NONE;
+ }
+ if (hw->addr.mode) {
+ if (hw->addr.p) {
+ release_mem_region(hw->addr.start, hw->addr.size);
+ iounmap(hw->addr.p);
+ } else
+ release_region(hw->addr.start, hw->addr.size);
+ hw->addr.mode = AM_NONE;
+ }
+}
+
+static int __devinit
+setup_io(struct inf_hw *hw)
+{
+ int err = 0;
+
+ if (hw->ci->cfg_mode) {
+ hw->cfg.start = pci_resource_start(hw->pdev, hw->ci->cfg_bar);
+ hw->cfg.size = pci_resource_len(hw->pdev, hw->ci->cfg_bar);
+ if (hw->ci->cfg_mode == AM_MEMIO) {
+ if (!request_mem_region(hw->cfg.start, hw->cfg.size,
+ hw->name))
+ err = -EBUSY;
+ } else {
+ if (!request_region(hw->cfg.start, hw->cfg.size,
+ hw->name))
+ err = -EBUSY;
+ }
+ if (err) {
+ pr_info("mISDN: %s config port %lx (%lu bytes)"
+ "already in use\n", hw->name,
+ (ulong)hw->cfg.start, (ulong)hw->cfg.size);
+ return err;
+ }
+ if (hw->ci->cfg_mode == AM_MEMIO)
+ hw->cfg.p = ioremap(hw->cfg.start, hw->cfg.size);
+ hw->cfg.mode = hw->ci->cfg_mode;
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IO cfg %lx (%lu bytes) mode%d\n",
+ hw->name, (ulong)hw->cfg.start,
+ (ulong)hw->cfg.size, hw->ci->cfg_mode);
+
+ }
+ if (hw->ci->addr_mode) {
+ hw->addr.start = pci_resource_start(hw->pdev, hw->ci->addr_bar);
+ hw->addr.size = pci_resource_len(hw->pdev, hw->ci->addr_bar);
+ if (hw->ci->addr_mode == AM_MEMIO) {
+ if (!request_mem_region(hw->addr.start, hw->addr.size,
+ hw->name))
+ err = -EBUSY;
+ } else {
+ if (!request_region(hw->addr.start, hw->addr.size,
+ hw->name))
+ err = -EBUSY;
+ }
+ if (err) {
+ pr_info("mISDN: %s address port %lx (%lu bytes)"
+ "already in use\n", hw->name,
+ (ulong)hw->addr.start, (ulong)hw->addr.size);
+ return err;
+ }
+ if (hw->ci->addr_mode == AM_MEMIO)
+ hw->addr.p = ioremap(hw->addr.start, hw->addr.size);
+ hw->addr.mode = hw->ci->addr_mode;
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IO addr %lx (%lu bytes) mode%d\n",
+ hw->name, (ulong)hw->addr.start,
+ (ulong)hw->addr.size, hw->ci->addr_mode);
+
+ }
+
+ switch (hw->ci->typ) {
+ case INF_DIVA20:
+ case INF_DIVA20U:
+ hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
+ hw->isac.mode = hw->cfg.mode;
+ hw->isac.a.io.ale = (u32)hw->cfg.start + DIVA_ISAC_ALE;
+ hw->isac.a.io.port = (u32)hw->cfg.start + DIVA_ISAC_PORT;
+ hw->hscx.mode = hw->cfg.mode;
+ hw->hscx.a.io.ale = (u32)hw->cfg.start + DIVA_HSCX_ALE;
+ hw->hscx.a.io.port = (u32)hw->cfg.start + DIVA_HSCX_PORT;
+ break;
+ case INF_DIVA201:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.p = hw->addr.p;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.p = hw->addr.p;
+ break;
+ case INF_DIVA202:
+ hw->ipac.type = IPAC_TYPE_IPACX;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.p = hw->addr.p;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.p = hw->addr.p;
+ break;
+ case INF_SPEEDWIN:
+ case INF_SAPHIR3:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.mode = hw->cfg.mode;
+ hw->isac.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;
+ hw->isac.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;
+ hw->hscx.mode = hw->cfg.mode;
+ hw->hscx.a.io.ale = (u32)hw->cfg.start + TIGER_IPAC_ALE;
+ hw->hscx.a.io.port = (u32)hw->cfg.start + TIGER_IPAC_PORT;
+ outb(0xff, (ulong)hw->cfg.start);
+ mdelay(1);
+ outb(0x00, (ulong)hw->cfg.start);
+ mdelay(1);
+ outb(TIGER_IOMASK, (ulong)hw->cfg.start + TIGER_AUX_CTRL);
+ break;
+ case INF_QS1000:
+ case INF_QS3000:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start;
+ hw->isac.a.io.port = (u32)hw->addr.start + 1;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = (u32)hw->addr.start;
+ hw->hscx.a.io.port = (u32)hw->addr.start + 1;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_NICCY:
+ hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.io.ale = (u32)hw->addr.start + NICCY_ISAC_ALE;
+ hw->isac.a.io.port = (u32)hw->addr.start + NICCY_ISAC_PORT;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = (u32)hw->addr.start + NICCY_HSCX_ALE;
+ hw->hscx.a.io.port = (u32)hw->addr.start + NICCY_HSCX_PORT;
+ break;
+ case INF_SCT_1:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start;
+ hw->isac.a.io.port = hw->isac.a.io.ale + 4;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_SCT_2:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start + 0x08;
+ hw->isac.a.io.port = hw->isac.a.io.ale + 4;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_SCT_3:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start + 0x10;
+ hw->isac.a.io.port = hw->isac.a.io.ale + 4;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_SCT_4:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.a.io.ale = (u32)hw->addr.start + 0x20;
+ hw->isac.a.io.port = hw->isac.a.io.ale + 4;
+ hw->isac.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ hw->hscx.mode = hw->addr.mode;
+ break;
+ case INF_GAZEL_R685:
+ hw->ipac.type = IPAC_TYPE_ISAC | IPAC_TYPE_HSCX;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.io.port = (u32)hw->addr.start;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ break;
+ case INF_GAZEL_R753:
+ hw->ipac.type = IPAC_TYPE_IPAC;
+ hw->ipac.isac.off = 0x80;
+ hw->isac.mode = hw->addr.mode;
+ hw->isac.a.io.ale = (u32)hw->addr.start;
+ hw->isac.a.io.port = (u32)hw->addr.start + GAZEL_IPAC_DATA_PORT;
+ hw->hscx.mode = hw->addr.mode;
+ hw->hscx.a.io.ale = hw->isac.a.io.ale;
+ hw->hscx.a.io.port = hw->isac.a.io.port;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (hw->isac.mode) {
+ case AM_MEMIO:
+ ASSIGN_FUNC_IPAC(MIO, hw->ipac);
+ break;
+ case AM_IND_IO:
+ ASSIGN_FUNC_IPAC(IND, hw->ipac);
+ break;
+ case AM_IO:
+ ASSIGN_FUNC_IPAC(IO, hw->ipac);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void
+release_card(struct inf_hw *card) {
+ ulong flags;
+ int i;
+
+ spin_lock_irqsave(&card->lock, flags);
+ disable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ card->ipac.isac.release(&card->ipac.isac);
+ free_irq(card->irq, card);
+ mISDN_unregister_device(&card->ipac.isac.dch.dev);
+ release_io(card);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ switch (card->ci->typ) {
+ case INF_SCT_2:
+ case INF_SCT_3:
+ case INF_SCT_4:
+ break;
+ case INF_SCT_1:
+ for (i = 0; i < 3; i++) {
+ if (card->sc[i])
+ release_card(card->sc[i]);
+ card->sc[i] = NULL;
+ }
+ default:
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ break;
+ }
+ kfree(card);
+ inf_cnt--;
+}
+
+static int __devinit
+setup_instance(struct inf_hw *card)
+{
+ int err;
+ ulong flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "%s.%d", card->ci->name,
+ inf_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+
+ _set_debug(card);
+ card->ipac.isac.name = card->name;
+ card->ipac.name = card->name;
+ card->ipac.owner = THIS_MODULE;
+ spin_lock_init(&card->lock);
+ card->ipac.isac.hwlock = &card->lock;
+ card->ipac.hwlock = &card->lock;
+ card->ipac.ctrl = (void *)&inf_ctrl;
+
+ err = setup_io(card);
+ if (err)
+ goto error_setup;
+
+ card->ipac.isac.dch.dev.Bprotocols =
+ mISDNipac_init(&card->ipac, card);
+
+ if (card->ipac.isac.dch.dev.Bprotocols == 0)
+ goto error_setup;;
+
+ err = mISDN_register_device(&card->ipac.isac.dch.dev,
+ &card->pdev->dev, card->name);
+ if (err)
+ goto error;
+
+ err = init_irq(card);
+ if (!err) {
+ inf_cnt++;
+ pr_notice("Infineon %d cards installed\n", inf_cnt);
+ return 0;
+ }
+ mISDN_unregister_device(&card->ipac.isac.dch.dev);
+error:
+ card->ipac.release(&card->ipac);
+error_setup:
+ release_io(card);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ return err;
+}
+
+static const struct inf_cinfo inf_card_info[] = {
+ {
+ INF_DIVA20,
+ "Dialogic Diva 2.0",
+ "diva20",
+ AM_IND_IO, AM_NONE, 2, 0,
+ &diva_irq
+ },
+ {
+ INF_DIVA20U,
+ "Dialogic Diva 2.0U",
+ "diva20U",
+ AM_IND_IO, AM_NONE, 2, 0,
+ &diva_irq
+ },
+ {
+ INF_DIVA201,
+ "Dialogic Diva 2.01",
+ "diva201",
+ AM_MEMIO, AM_MEMIO, 0, 1,
+ &diva20x_irq
+ },
+ {
+ INF_DIVA202,
+ "Dialogic Diva 2.02",
+ "diva202",
+ AM_MEMIO, AM_MEMIO, 0, 1,
+ &diva20x_irq
+ },
+ {
+ INF_SPEEDWIN,
+ "Sedlbauer SpeedWin PCI",
+ "speedwin",
+ AM_IND_IO, AM_NONE, 0, 0,
+ &tiger_irq
+ },
+ {
+ INF_SAPHIR3,
+ "HST Saphir 3",
+ "saphir",
+ AM_IND_IO, AM_NONE, 0, 0,
+ &tiger_irq
+ },
+ {
+ INF_QS1000,
+ "Develo Microlink PCI",
+ "qs1000",
+ AM_IO, AM_IND_IO, 1, 3,
+ &elsa_irq
+ },
+ {
+ INF_QS3000,
+ "Develo QuickStep 3000",
+ "qs3000",
+ AM_IO, AM_IND_IO, 1, 3,
+ &elsa_irq
+ },
+ {
+ INF_NICCY,
+ "Sagem NICCY",
+ "niccy",
+ AM_IO, AM_IND_IO, 0, 1,
+ &niccy_irq
+ },
+ {
+ INF_SCT_1,
+ "SciTel Quadro",
+ "p1_scitel",
+ AM_IO, AM_IND_IO, 1, 5,
+ &ipac_irq
+ },
+ {
+ INF_SCT_2,
+ "SciTel Quadro",
+ "p2_scitel",
+ AM_NONE, AM_IND_IO, 0, 4,
+ &ipac_irq
+ },
+ {
+ INF_SCT_3,
+ "SciTel Quadro",
+ "p3_scitel",
+ AM_NONE, AM_IND_IO, 0, 3,
+ &ipac_irq
+ },
+ {
+ INF_SCT_4,
+ "SciTel Quadro",
+ "p4_scitel",
+ AM_NONE, AM_IND_IO, 0, 2,
+ &ipac_irq
+ },
+ {
+ INF_GAZEL_R685,
+ "Gazel R685",
+ "gazel685",
+ AM_IO, AM_IO, 1, 2,
+ &gazel_irq
+ },
+ {
+ INF_GAZEL_R753,
+ "Gazel R753",
+ "gazel753",
+ AM_IO, AM_IND_IO, 1, 2,
+ &ipac_irq
+ },
+ {
+ INF_NONE,
+ }
+};
+
+static const struct inf_cinfo * __devinit
+get_card_info(enum inf_types typ)
+{
+ const struct inf_cinfo *ci = inf_card_info;
+
+ while (ci->typ != INF_NONE) {
+ if (ci->typ == typ)
+ return ci;
+ ci++;
+ }
+ return NULL;
+}
+
+static int __devinit
+inf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ struct inf_hw *card;
+
+ card = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);
+ if (!card) {
+ pr_info("No memory for Infineon ISDN card\n");
+ return err;
+ }
+ card->pdev = pdev;
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+ card->ci = get_card_info(ent->driver_data);
+ if (!card->ci) {
+ pr_info("mISDN: do not have informations about adapter at %s\n",
+ pci_name(pdev));
+ kfree(card);
+ return -EINVAL;
+ } else
+ pr_notice("mISDN: found adapter %s at %s\n",
+ card->ci->full, pci_name(pdev));
+
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err) {
+ pci_disable_device(card->pdev);
+ kfree(card);
+ pci_set_drvdata(pdev, NULL);
+ } else if (ent->driver_data == INF_SCT_1) {
+ int i;
+ struct inf_hw *sc;
+
+ for (i = 1; i < 4; i++) {
+ sc = kzalloc(sizeof(struct inf_hw), GFP_KERNEL);
+ if (!sc) {
+ release_card(card);
+ return -ENOMEM;
+ }
+ sc->irq = card->irq;
+ sc->pdev = card->pdev;
+ sc->ci = card->ci + i;
+ err = setup_instance(sc);
+ if (err) {
+ kfree(sc);
+ release_card(card);
+ } else
+ card->sc[i - 1] = sc;
+ }
+ }
+ return err;
+}
+
+static void __devexit
+inf_remove(struct pci_dev *pdev)
+{
+ struct inf_hw *card = pci_get_drvdata(pdev);
+
+ if (card)
+ release_card(card);
+ else
+ pr_debug("%s: drvdata allready removed\n", __func__);
+}
+
+static struct pci_driver infineon_driver = {
+ .name = "ISDN Infineon pci",
+ .probe = inf_probe,
+ .remove = __devexit_p(inf_remove),
+ .id_table = infineon_ids,
+};
+
+static int __init
+infineon_init(void)
+{
+ int err;
+
+ pr_notice("Infineon ISDN Driver Rev. %s\n", INFINEON_REV);
+ err = pci_register_driver(&infineon_driver);
+ return err;
+}
+
+static void __exit
+infineon_cleanup(void)
+{
+ pci_unregister_driver(&infineon_driver);
+}
+
+module_init(infineon_init);
+module_exit(infineon_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
new file mode 100644
index 00000000000..613ba043537
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -0,0 +1,1655 @@
+/*
+ * isac.c ISAC specific routines
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mISDNhw.h>
+#include "ipac.h"
+
+
+#define DBUSY_TIMER_VALUE 80
+#define ARCOFI_USE 1
+
+#define ISAC_REV "2.0"
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_VERSION(ISAC_REV);
+MODULE_LICENSE("GPL v2");
+
+#define ReadISAC(is, o) (is->read_reg(is->dch.hw, o + is->off))
+#define WriteISAC(is, o, v) (is->write_reg(is->dch.hw, o + is->off, v))
+#define ReadHSCX(h, o) (h->ip->read_reg(h->ip->hw, h->off + o))
+#define WriteHSCX(h, o, v) (h->ip->write_reg(h->ip->hw, h->off + o, v))
+#define ReadIPAC(ip, o) (ip->read_reg(ip->hw, o))
+#define WriteIPAC(ip, o, v) (ip->write_reg(ip->hw, o, v))
+
+static inline void
+ph_command(struct isac_hw *isac, u8 command)
+{
+ pr_debug("%s: ph_command %x\n", isac->name, command);
+ if (isac->type & IPAC_TYPE_ISACX)
+ WriteISAC(isac, ISACX_CIX0, (command << 4) | 0xE);
+ else
+ WriteISAC(isac, ISAC_CIX0, (command << 2) | 3);
+}
+
+static void
+isac_ph_state_change(struct isac_hw *isac)
+{
+ switch (isac->state) {
+ case (ISAC_IND_RS):
+ case (ISAC_IND_EI):
+ ph_command(isac, ISAC_CMD_DUI);
+ }
+ schedule_event(&isac->dch, FLG_PHCHANGE);
+}
+
+static void
+isac_ph_state_bh(struct dchannel *dch)
+{
+ struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
+
+ switch (isac->state) {
+ case ISAC_IND_RS:
+ case ISAC_IND_EI:
+ dch->state = 0;
+ l1_event(dch->l1, HW_RESET_IND);
+ break;
+ case ISAC_IND_DID:
+ dch->state = 3;
+ l1_event(dch->l1, HW_DEACT_CNF);
+ break;
+ case ISAC_IND_DR:
+ dch->state = 3;
+ l1_event(dch->l1, HW_DEACT_IND);
+ break;
+ case ISAC_IND_PU:
+ dch->state = 4;
+ l1_event(dch->l1, HW_POWERUP_IND);
+ break;
+ case ISAC_IND_RSY:
+ if (dch->state <= 5) {
+ dch->state = 5;
+ l1_event(dch->l1, ANYSIGNAL);
+ } else {
+ dch->state = 8;
+ l1_event(dch->l1, LOSTFRAMING);
+ }
+ break;
+ case ISAC_IND_ARD:
+ dch->state = 6;
+ l1_event(dch->l1, INFO2);
+ break;
+ case ISAC_IND_AI8:
+ dch->state = 7;
+ l1_event(dch->l1, INFO4_P8);
+ break;
+ case ISAC_IND_AI10:
+ dch->state = 7;
+ l1_event(dch->l1, INFO4_P10);
+ break;
+ }
+ pr_debug("%s: TE newstate %x\n", isac->name, dch->state);
+}
+
+void
+isac_empty_fifo(struct isac_hw *isac, int count)
+{
+ u8 *ptr;
+
+ pr_debug("%s: %s %d\n", isac->name, __func__, count);
+
+ if (!isac->dch.rx_skb) {
+ isac->dch.rx_skb = mI_alloc_skb(isac->dch.maxlen, GFP_ATOMIC);
+ if (!isac->dch.rx_skb) {
+ pr_info("%s: D receive out of memory\n", isac->name);
+ WriteISAC(isac, ISAC_CMDR, 0x80);
+ return;
+ }
+ }
+ if ((isac->dch.rx_skb->len + count) >= isac->dch.maxlen) {
+ pr_debug("%s: %s overrun %d\n", isac->name, __func__,
+ isac->dch.rx_skb->len + count);
+ WriteISAC(isac, ISAC_CMDR, 0x80);
+ return;
+ }
+ ptr = skb_put(isac->dch.rx_skb, count);
+ isac->read_fifo(isac->dch.hw, isac->off, ptr, count);
+ WriteISAC(isac, ISAC_CMDR, 0x80);
+ if (isac->dch.debug & DEBUG_HW_DFIFO) {
+ char pfx[MISDN_MAX_IDLEN + 16];
+
+ snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-recv %s %d ",
+ isac->name, count);
+ print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+isac_fill_fifo(struct isac_hw *isac)
+{
+ int count, more;
+ u8 *ptr;
+
+ if (!isac->dch.tx_skb)
+ return;
+ count = isac->dch.tx_skb->len - isac->dch.tx_idx;
+ if (count <= 0)
+ return;
+
+ more = 0;
+ if (count > 32) {
+ more = !0;
+ count = 32;
+ }
+ pr_debug("%s: %s %d\n", isac->name, __func__, count);
+ ptr = isac->dch.tx_skb->data + isac->dch.tx_idx;
+ isac->dch.tx_idx += count;
+ isac->write_fifo(isac->dch.hw, isac->off, ptr, count);
+ WriteISAC(isac, ISAC_CMDR, more ? 0x8 : 0xa);
+ if (test_and_set_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {
+ pr_debug("%s: %s dbusytimer running\n", isac->name, __func__);
+ del_timer(&isac->dch.timer);
+ }
+ init_timer(&isac->dch.timer);
+ isac->dch.timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+ add_timer(&isac->dch.timer);
+ if (isac->dch.debug & DEBUG_HW_DFIFO) {
+ char pfx[MISDN_MAX_IDLEN + 16];
+
+ snprintf(pfx, MISDN_MAX_IDLEN + 15, "D-send %s %d ",
+ isac->name, count);
+ print_hex_dump_bytes(pfx, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+isac_rme_irq(struct isac_hw *isac)
+{
+ u8 val, count;
+
+ val = ReadISAC(isac, ISAC_RSTA);
+ if ((val & 0x70) != 0x20) {
+ if (val & 0x40) {
+ pr_debug("%s: ISAC RDO\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_rx++;
+#endif
+ }
+ if (!(val & 0x20)) {
+ pr_debug("%s: ISAC CRC error\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_crc++;
+#endif
+ }
+ WriteISAC(isac, ISAC_CMDR, 0x80);
+ if (isac->dch.rx_skb)
+ dev_kfree_skb(isac->dch.rx_skb);
+ isac->dch.rx_skb = NULL;
+ } else {
+ count = ReadISAC(isac, ISAC_RBCL) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(isac, count);
+ recv_Dchannel(&isac->dch);
+ }
+}
+
+static void
+isac_xpr_irq(struct isac_hw *isac)
+{
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))
+ del_timer(&isac->dch.timer);
+ if (isac->dch.tx_skb && isac->dch.tx_idx < isac->dch.tx_skb->len) {
+ isac_fill_fifo(isac);
+ } else {
+ if (isac->dch.tx_skb)
+ dev_kfree_skb(isac->dch.tx_skb);
+ if (get_next_dframe(&isac->dch))
+ isac_fill_fifo(isac);
+ }
+}
+
+static void
+isac_retransmit(struct isac_hw *isac)
+{
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags))
+ del_timer(&isac->dch.timer);
+ if (test_bit(FLG_TX_BUSY, &isac->dch.Flags)) {
+ /* Restart frame */
+ isac->dch.tx_idx = 0;
+ isac_fill_fifo(isac);
+ } else if (isac->dch.tx_skb) { /* should not happen */
+ pr_info("%s: tx_skb exist but not busy\n", isac->name);
+ test_and_set_bit(FLG_TX_BUSY, &isac->dch.Flags);
+ isac->dch.tx_idx = 0;
+ isac_fill_fifo(isac);
+ } else {
+ pr_info("%s: ISAC XDU no TX_BUSY\n", isac->name);
+ if (get_next_dframe(&isac->dch))
+ isac_fill_fifo(isac);
+ }
+}
+
+static void
+isac_mos_irq(struct isac_hw *isac)
+{
+ u8 val;
+ int ret;
+
+ val = ReadISAC(isac, ISAC_MOSR);
+ pr_debug("%s: ISAC MOSR %02x\n", isac->name, val);
+#if ARCOFI_USE
+ if (val & 0x08) {
+ if (!isac->mon_rx) {
+ isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
+ if (!isac->mon_rx) {
+ pr_info("%s: ISAC MON RX out of memory!\n",
+ isac->name);
+ isac->mocr &= 0xf0;
+ isac->mocr |= 0x0a;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ goto afterMONR0;
+ } else
+ isac->mon_rxp = 0;
+ }
+ if (isac->mon_rxp >= MAX_MON_FRAME) {
+ isac->mocr &= 0xf0;
+ isac->mocr |= 0x0a;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mon_rxp = 0;
+ pr_debug("%s: ISAC MON RX overflow!\n", isac->name);
+ goto afterMONR0;
+ }
+ isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR0);
+ pr_debug("%s: ISAC MOR0 %02x\n", isac->name,
+ isac->mon_rx[isac->mon_rxp - 1]);
+ if (isac->mon_rxp == 1) {
+ isac->mocr |= 0x04;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ }
+ }
+afterMONR0:
+ if (val & 0x80) {
+ if (!isac->mon_rx) {
+ isac->mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC);
+ if (!isac->mon_rx) {
+ pr_info("%s: ISAC MON RX out of memory!\n",
+ isac->name);
+ isac->mocr &= 0x0f;
+ isac->mocr |= 0xa0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ goto afterMONR1;
+ } else
+ isac->mon_rxp = 0;
+ }
+ if (isac->mon_rxp >= MAX_MON_FRAME) {
+ isac->mocr &= 0x0f;
+ isac->mocr |= 0xa0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mon_rxp = 0;
+ pr_debug("%s: ISAC MON RX overflow!\n", isac->name);
+ goto afterMONR1;
+ }
+ isac->mon_rx[isac->mon_rxp++] = ReadISAC(isac, ISAC_MOR1);
+ pr_debug("%s: ISAC MOR1 %02x\n", isac->name,
+ isac->mon_rx[isac->mon_rxp - 1]);
+ isac->mocr |= 0x40;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ }
+afterMONR1:
+ if (val & 0x04) {
+ isac->mocr &= 0xf0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mocr |= 0x0a;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ if (isac->monitor) {
+ ret = isac->monitor(isac->dch.hw, MONITOR_RX_0,
+ isac->mon_rx, isac->mon_rxp);
+ if (ret)
+ kfree(isac->mon_rx);
+ } else {
+ pr_info("%s: MONITOR 0 received %d but no user\n",
+ isac->name, isac->mon_rxp);
+ kfree(isac->mon_rx);
+ }
+ isac->mon_rx = NULL;
+ isac->mon_rxp = 0;
+ }
+ if (val & 0x40) {
+ isac->mocr &= 0x0f;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mocr |= 0xa0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ if (isac->monitor) {
+ ret = isac->monitor(isac->dch.hw, MONITOR_RX_1,
+ isac->mon_rx, isac->mon_rxp);
+ if (ret)
+ kfree(isac->mon_rx);
+ } else {
+ pr_info("%s: MONITOR 1 received %d but no user\n",
+ isac->name, isac->mon_rxp);
+ kfree(isac->mon_rx);
+ }
+ isac->mon_rx = NULL;
+ isac->mon_rxp = 0;
+ }
+ if (val & 0x02) {
+ if ((!isac->mon_tx) || (isac->mon_txc &&
+ (isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) {
+ isac->mocr &= 0xf0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mocr |= 0x0a;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+ if (isac->monitor)
+ ret = isac->monitor(isac->dch.hw,
+ MONITOR_TX_0, NULL, 0);
+ }
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ isac->mon_txc = 0;
+ isac->mon_txp = 0;
+ goto AfterMOX0;
+ }
+ if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+ if (isac->monitor)
+ ret = isac->monitor(isac->dch.hw,
+ MONITOR_TX_0, NULL, 0);
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ isac->mon_txc = 0;
+ isac->mon_txp = 0;
+ goto AfterMOX0;
+ }
+ WriteISAC(isac, ISAC_MOX0, isac->mon_tx[isac->mon_txp++]);
+ pr_debug("%s: ISAC %02x -> MOX0\n", isac->name,
+ isac->mon_tx[isac->mon_txp - 1]);
+ }
+AfterMOX0:
+ if (val & 0x20) {
+ if ((!isac->mon_tx) || (isac->mon_txc &&
+ (isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) {
+ isac->mocr &= 0x0f;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ isac->mocr |= 0xa0;
+ WriteISAC(isac, ISAC_MOCR, isac->mocr);
+ if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+ if (isac->monitor)
+ ret = isac->monitor(isac->dch.hw,
+ MONITOR_TX_1, NULL, 0);
+ }
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ isac->mon_txc = 0;
+ isac->mon_txp = 0;
+ goto AfterMOX1;
+ }
+ if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
+ if (isac->monitor)
+ ret = isac->monitor(isac->dch.hw,
+ MONITOR_TX_1, NULL, 0);
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ isac->mon_txc = 0;
+ isac->mon_txp = 0;
+ goto AfterMOX1;
+ }
+ WriteISAC(isac, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
+ pr_debug("%s: ISAC %02x -> MOX1\n", isac->name,
+ isac->mon_tx[isac->mon_txp - 1]);
+ }
+AfterMOX1:
+ val = 0; /* dummy to avoid warning */
+#endif
+}
+
+static void
+isac_cisq_irq(struct isac_hw *isac) {
+ u8 val;
+
+ val = ReadISAC(isac, ISAC_CIR0);
+ pr_debug("%s: ISAC CIR0 %02X\n", isac->name, val);
+ if (val & 2) {
+ pr_debug("%s: ph_state change %x->%x\n", isac->name,
+ isac->state, (val >> 2) & 0xf);
+ isac->state = (val >> 2) & 0xf;
+ isac_ph_state_change(isac);
+ }
+ if (val & 1) {
+ val = ReadISAC(isac, ISAC_CIR1);
+ pr_debug("%s: ISAC CIR1 %02X\n", isac->name, val);
+ }
+}
+
+static void
+isacsx_cic_irq(struct isac_hw *isac)
+{
+ u8 val;
+
+ val = ReadISAC(isac, ISACX_CIR0);
+ pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);
+ if (val & ISACX_CIR0_CIC0) {
+ pr_debug("%s: ph_state change %x->%x\n", isac->name,
+ isac->state, val >> 4);
+ isac->state = val >> 4;
+ isac_ph_state_change(isac);
+ }
+}
+
+static void
+isacsx_rme_irq(struct isac_hw *isac)
+{
+ int count;
+ u8 val;
+
+ val = ReadISAC(isac, ISACX_RSTAD);
+ if ((val & (ISACX_RSTAD_VFR |
+ ISACX_RSTAD_RDO |
+ ISACX_RSTAD_CRC |
+ ISACX_RSTAD_RAB))
+ != (ISACX_RSTAD_VFR | ISACX_RSTAD_CRC)) {
+ pr_debug("%s: RSTAD %#x, dropped\n", isac->name, val);
+#ifdef ERROR_STATISTIC
+ if (val & ISACX_RSTAD_CRC)
+ isac->dch.err_rx++;
+ else
+ isac->dch.err_crc++;
+#endif
+ WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);
+ if (isac->dch.rx_skb)
+ dev_kfree_skb(isac->dch.rx_skb);
+ isac->dch.rx_skb = NULL;
+ } else {
+ count = ReadISAC(isac, ISACX_RBCLD) & 0x1f;
+ if (count == 0)
+ count = 32;
+ isac_empty_fifo(isac, count);
+ if (isac->dch.rx_skb) {
+ skb_trim(isac->dch.rx_skb, isac->dch.rx_skb->len - 1);
+ pr_debug("%s: dchannel received %d\n", isac->name,
+ isac->dch.rx_skb->len);
+ recv_Dchannel(&isac->dch);
+ }
+ }
+}
+
+irqreturn_t
+mISDNisac_irq(struct isac_hw *isac, u8 val)
+{
+ if (unlikely(!val))
+ return IRQ_NONE;
+ pr_debug("%s: ISAC interrupt %02x\n", isac->name, val);
+ if (isac->type & IPAC_TYPE_ISACX) {
+ if (val & ISACX__CIC)
+ isacsx_cic_irq(isac);
+ if (val & ISACX__ICD) {
+ val = ReadISAC(isac, ISACX_ISTAD);
+ pr_debug("%s: ISTAD %02x\n", isac->name, val);
+ if (val & ISACX_D_XDU) {
+ pr_debug("%s: ISAC XDU\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_tx++;
+#endif
+ isac_retransmit(isac);
+ }
+ if (val & ISACX_D_XMR) {
+ pr_debug("%s: ISAC XMR\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_tx++;
+#endif
+ isac_retransmit(isac);
+ }
+ if (val & ISACX_D_XPR)
+ isac_xpr_irq(isac);
+ if (val & ISACX_D_RFO) {
+ pr_debug("%s: ISAC RFO\n", isac->name);
+ WriteISAC(isac, ISACX_CMDRD, ISACX_CMDRD_RMC);
+ }
+ if (val & ISACX_D_RME)
+ isacsx_rme_irq(isac);
+ if (val & ISACX_D_RPF)
+ isac_empty_fifo(isac, 0x20);
+ }
+ } else {
+ if (val & 0x80) /* RME */
+ isac_rme_irq(isac);
+ if (val & 0x40) /* RPF */
+ isac_empty_fifo(isac, 32);
+ if (val & 0x10) /* XPR */
+ isac_xpr_irq(isac);
+ if (val & 0x04) /* CISQ */
+ isac_cisq_irq(isac);
+ if (val & 0x20) /* RSC - never */
+ pr_debug("%s: ISAC RSC interrupt\n", isac->name);
+ if (val & 0x02) /* SIN - never */
+ pr_debug("%s: ISAC SIN interrupt\n", isac->name);
+ if (val & 0x01) { /* EXI */
+ val = ReadISAC(isac, ISAC_EXIR);
+ pr_debug("%s: ISAC EXIR %02x\n", isac->name, val);
+ if (val & 0x80) /* XMR */
+ pr_debug("%s: ISAC XMR\n", isac->name);
+ if (val & 0x40) { /* XDU */
+ pr_debug("%s: ISAC XDU\n", isac->name);
+#ifdef ERROR_STATISTIC
+ isac->dch.err_tx++;
+#endif
+ isac_retransmit(isac);
+ }
+ if (val & 0x04) /* MOS */
+ isac_mos_irq(isac);
+ }
+ }
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(mISDNisac_irq);
+
+static int
+isac_l1hw(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(isac->hwlock, flags);
+ ret = dchannel_senddata(dch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ isac_fill_fifo(isac);
+ ret = 0;
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ case PH_DEACTIVATE_REQ:
+ test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ }
+
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+isac_ctrl(struct isac_hw *isac, u32 cmd, u_long para)
+{
+ u8 tl = 0;
+ u_long flags;
+
+ switch (cmd) {
+ case HW_TESTLOOP:
+ spin_lock_irqsave(isac->hwlock, flags);
+ if (!(isac->type & IPAC_TYPE_ISACX)) {
+ /* TODO: implement for IPAC_TYPE_ISACX */
+ if (para & 1) /* B1 */
+ tl |= 0x0c;
+ else if (para & 2) /* B2 */
+ tl |= 0x3;
+ /* we only support IOM2 mode */
+ WriteISAC(isac, ISAC_SPCR, tl);
+ if (tl)
+ WriteISAC(isac, ISAC_ADF1, 0x8);
+ else
+ WriteISAC(isac, ISAC_ADF1, 0x0);
+ }
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x %lx\n", isac->name,
+ __func__, cmd, para);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+isac_l1cmd(struct dchannel *dch, u32 cmd)
+{
+ struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
+ u_long flags;
+
+ pr_debug("%s: cmd(%x) state(%02x)\n", isac->name, cmd, isac->state);
+ switch (cmd) {
+ case INFO3_P8:
+ spin_lock_irqsave(isac->hwlock, flags);
+ ph_command(isac, ISAC_CMD_AR8);
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ case INFO3_P10:
+ spin_lock_irqsave(isac->hwlock, flags);
+ ph_command(isac, ISAC_CMD_AR10);
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ case HW_RESET_REQ:
+ spin_lock_irqsave(isac->hwlock, flags);
+ if ((isac->state == ISAC_IND_EI) ||
+ (isac->state == ISAC_IND_DR) ||
+ (isac->state == ISAC_IND_RS))
+ ph_command(isac, ISAC_CMD_TIM);
+ else
+ ph_command(isac, ISAC_CMD_RS);
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ case HW_DEACT_REQ:
+ skb_queue_purge(&dch->squeue);
+ if (dch->tx_skb) {
+ dev_kfree_skb(dch->tx_skb);
+ dch->tx_skb = NULL;
+ }
+ dch->tx_idx = 0;
+ if (dch->rx_skb) {
+ dev_kfree_skb(dch->rx_skb);
+ dch->rx_skb = NULL;
+ }
+ test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+ del_timer(&dch->timer);
+ break;
+ case HW_POWERUP_REQ:
+ spin_lock_irqsave(isac->hwlock, flags);
+ ph_command(isac, ISAC_CMD_TIM);
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ break;
+ case PH_ACTIVATE_IND:
+ test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ case PH_DEACTIVATE_IND:
+ test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x\n", isac->name,
+ __func__, cmd);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+isac_release(struct isac_hw *isac)
+{
+ if (isac->type & IPAC_TYPE_ISACX)
+ WriteISAC(isac, ISACX_MASK, 0xff);
+ else
+ WriteISAC(isac, ISAC_MASK, 0xff);
+ if (isac->dch.timer.function != NULL) {
+ del_timer(&isac->dch.timer);
+ isac->dch.timer.function = NULL;
+ }
+ kfree(isac->mon_rx);
+ isac->mon_rx = NULL;
+ kfree(isac->mon_tx);
+ isac->mon_tx = NULL;
+ if (isac->dch.l1)
+ l1_event(isac->dch.l1, CLOSE_CHANNEL);
+ mISDN_freedchannel(&isac->dch);
+}
+
+static void
+dbusy_timer_handler(struct isac_hw *isac)
+{
+ int rbch, star;
+ u_long flags;
+
+ if (test_bit(FLG_BUSY_TIMER, &isac->dch.Flags)) {
+ spin_lock_irqsave(isac->hwlock, flags);
+ rbch = ReadISAC(isac, ISAC_RBCH);
+ star = ReadISAC(isac, ISAC_STAR);
+ pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",
+ isac->name, rbch, star);
+ if (rbch & ISAC_RBCH_XAC) /* D-Channel Busy */
+ test_and_set_bit(FLG_L1_BUSY, &isac->dch.Flags);
+ else {
+ /* discard frame; reset transceiver */
+ test_and_clear_bit(FLG_BUSY_TIMER, &isac->dch.Flags);
+ if (isac->dch.tx_idx)
+ isac->dch.tx_idx = 0;
+ else
+ pr_info("%s: ISAC D-Channel Busy no tx_idx\n",
+ isac->name);
+ /* Transmitter reset */
+ WriteISAC(isac, ISAC_CMDR, 0x01);
+ }
+ spin_unlock_irqrestore(isac->hwlock, flags);
+ }
+}
+
+static int
+open_dchannel(struct isac_hw *isac, struct channel_req *rq)
+{
+ pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__,
+ isac->dch.dev.id, __builtin_return_address(1));
+ if (rq->protocol != ISDN_P_TE_S0)
+ return -EINVAL;
+ if (rq->adr.channel == 1)
+ /* E-Channel not supported */
+ return -EINVAL;
+ rq->ch = &isac->dch.dev.D;
+ rq->ch->protocol = rq->protocol;
+ if (isac->dch.state == 7)
+ _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
+ 0, NULL, GFP_KERNEL);
+ return 0;
+}
+
+static const char *ISACVer[] =
+{"2086/2186 V1.1", "2085 B1", "2085 B2",
+ "2085 V2.3"};
+
+static int
+isac_init(struct isac_hw *isac)
+{
+ u8 val;
+ int err = 0;
+
+ if (!isac->dch.l1) {
+ err = create_l1(&isac->dch, isac_l1cmd);
+ if (err)
+ return err;
+ }
+ isac->mon_tx = NULL;
+ isac->mon_rx = NULL;
+ isac->dch.timer.function = (void *) dbusy_timer_handler;
+ isac->dch.timer.data = (long)isac;
+ init_timer(&isac->dch.timer);
+ isac->mocr = 0xaa;
+ if (isac->type & IPAC_TYPE_ISACX) {
+ /* Disable all IRQ */
+ WriteISAC(isac, ISACX_MASK, 0xff);
+ val = ReadISAC(isac, ISACX_STARD);
+ pr_debug("%s: ISACX STARD %x\n", isac->name, val);
+ val = ReadISAC(isac, ISACX_ISTAD);
+ pr_debug("%s: ISACX ISTAD %x\n", isac->name, val);
+ val = ReadISAC(isac, ISACX_ISTA);
+ pr_debug("%s: ISACX ISTA %x\n", isac->name, val);
+ /* clear LDD */
+ WriteISAC(isac, ISACX_TR_CONF0, 0x00);
+ /* enable transmitter */
+ WriteISAC(isac, ISACX_TR_CONF2, 0x00);
+ /* transparent mode 0, RAC, stop/go */
+ WriteISAC(isac, ISACX_MODED, 0xc9);
+ /* all HDLC IRQ unmasked */
+ val = ReadISAC(isac, ISACX_ID);
+ if (isac->dch.debug & DEBUG_HW)
+ pr_notice("%s: ISACX Design ID %x\n",
+ isac->name, val & 0x3f);
+ val = ReadISAC(isac, ISACX_CIR0);
+ pr_debug("%s: ISACX CIR0 %02X\n", isac->name, val);
+ isac->state = val >> 4;
+ isac_ph_state_change(isac);
+ ph_command(isac, ISAC_CMD_RS);
+ WriteISAC(isac, ISACX_MASK, IPACX__ON);
+ WriteISAC(isac, ISACX_MASKD, 0x00);
+ } else { /* old isac */
+ WriteISAC(isac, ISAC_MASK, 0xff);
+ val = ReadISAC(isac, ISAC_STAR);
+ pr_debug("%s: ISAC STAR %x\n", isac->name, val);
+ val = ReadISAC(isac, ISAC_MODE);
+ pr_debug("%s: ISAC MODE %x\n", isac->name, val);
+ val = ReadISAC(isac, ISAC_ADF2);
+ pr_debug("%s: ISAC ADF2 %x\n", isac->name, val);
+ val = ReadISAC(isac, ISAC_ISTA);
+ pr_debug("%s: ISAC ISTA %x\n", isac->name, val);
+ if (val & 0x01) {
+ val = ReadISAC(isac, ISAC_EXIR);
+ pr_debug("%s: ISAC EXIR %x\n", isac->name, val);
+ }
+ val = ReadISAC(isac, ISAC_RBCH);
+ if (isac->dch.debug & DEBUG_HW)
+ pr_notice("%s: ISAC version (%x): %s\n", isac->name,
+ val, ISACVer[(val >> 5) & 3]);
+ isac->type |= ((val >> 5) & 3);
+ if (!isac->adf2)
+ isac->adf2 = 0x80;
+ if (!(isac->adf2 & 0x80)) { /* only IOM 2 Mode */
+ pr_info("%s: only support IOM2 mode but adf2=%02x\n",
+ isac->name, isac->adf2);
+ isac_release(isac);
+ return -EINVAL;
+ }
+ WriteISAC(isac, ISAC_ADF2, isac->adf2);
+ WriteISAC(isac, ISAC_SQXR, 0x2f);
+ WriteISAC(isac, ISAC_SPCR, 0x00);
+ WriteISAC(isac, ISAC_STCR, 0x70);
+ WriteISAC(isac, ISAC_MODE, 0xc9);
+ WriteISAC(isac, ISAC_TIMR, 0x00);
+ WriteISAC(isac, ISAC_ADF1, 0x00);
+ val = ReadISAC(isac, ISAC_CIR0);
+ pr_debug("%s: ISAC CIR0 %x\n", isac->name, val);
+ isac->state = (val >> 2) & 0xf;
+ isac_ph_state_change(isac);
+ ph_command(isac, ISAC_CMD_RS);
+ WriteISAC(isac, ISAC_MASK, 0);
+ }
+ return err;
+}
+
+int
+mISDNisac_init(struct isac_hw *isac, void *hw)
+{
+ mISDN_initdchannel(&isac->dch, MAX_DFRAME_LEN_L1, isac_ph_state_bh);
+ isac->dch.hw = hw;
+ isac->dch.dev.D.send = isac_l1hw;
+ isac->init = isac_init;
+ isac->release = isac_release;
+ isac->ctrl = isac_ctrl;
+ isac->open = open_dchannel;
+ isac->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);
+ isac->dch.dev.nrbchan = 2;
+ return 0;
+}
+EXPORT_SYMBOL(mISDNisac_init);
+
+static void
+waitforCEC(struct hscx_hw *hx)
+{
+ u8 starb, to = 50;
+
+ while (to) {
+ starb = ReadHSCX(hx, IPAC_STARB);
+ if (!(starb & 0x04))
+ break;
+ udelay(1);
+ to--;
+ }
+ if (to < 50)
+ pr_debug("%s: B%1d CEC %d us\n", hx->ip->name, hx->bch.nr,
+ 50 - to);
+ if (!to)
+ pr_info("%s: B%1d CEC timeout\n", hx->ip->name, hx->bch.nr);
+}
+
+
+static void
+waitforXFW(struct hscx_hw *hx)
+{
+ u8 starb, to = 50;
+
+ while (to) {
+ starb = ReadHSCX(hx, IPAC_STARB);
+ if ((starb & 0x44) == 0x40)
+ break;
+ udelay(1);
+ to--;
+ }
+ if (to < 50)
+ pr_debug("%s: B%1d XFW %d us\n", hx->ip->name, hx->bch.nr,
+ 50 - to);
+ if (!to)
+ pr_info("%s: B%1d XFW timeout\n", hx->ip->name, hx->bch.nr);
+}
+
+static void
+hscx_cmdr(struct hscx_hw *hx, u8 cmd)
+{
+ if (hx->ip->type & IPAC_TYPE_IPACX)
+ WriteHSCX(hx, IPACX_CMDRB, cmd);
+ else {
+ waitforCEC(hx);
+ WriteHSCX(hx, IPAC_CMDRB, cmd);
+ }
+}
+
+static void
+hscx_empty_fifo(struct hscx_hw *hscx, u8 count)
+{
+ u8 *p;
+
+ pr_debug("%s: B%1d %d\n", hscx->ip->name, hscx->bch.nr, count);
+ if (!hscx->bch.rx_skb) {
+ hscx->bch.rx_skb = mI_alloc_skb(hscx->bch.maxlen, GFP_ATOMIC);
+ if (!hscx->bch.rx_skb) {
+ pr_info("%s: B receive out of memory\n",
+ hscx->ip->name);
+ hscx_cmdr(hscx, 0x80); /* RMC */
+ return;
+ }
+ }
+ if ((hscx->bch.rx_skb->len + count) > hscx->bch.maxlen) {
+ pr_debug("%s: overrun %d\n", hscx->ip->name,
+ hscx->bch.rx_skb->len + count);
+ skb_trim(hscx->bch.rx_skb, 0);
+ hscx_cmdr(hscx, 0x80); /* RMC */
+ return;
+ }
+ p = skb_put(hscx->bch.rx_skb, count);
+
+ if (hscx->ip->type & IPAC_TYPE_IPACX)
+ hscx->ip->read_fifo(hscx->ip->hw,
+ hscx->off + IPACX_RFIFOB, p, count);
+ else
+ hscx->ip->read_fifo(hscx->ip->hw,
+ hscx->off, p, count);
+
+ hscx_cmdr(hscx, 0x80); /* RMC */
+
+ if (hscx->bch.debug & DEBUG_HW_BFIFO) {
+ snprintf(hscx->log, 64, "B%1d-recv %s %d ",
+ hscx->bch.nr, hscx->ip->name, count);
+ print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+hscx_fill_fifo(struct hscx_hw *hscx)
+{
+ int count, more;
+ u8 *p;
+
+ if (!hscx->bch.tx_skb)
+ return;
+ count = hscx->bch.tx_skb->len - hscx->bch.tx_idx;
+ if (count <= 0)
+ return;
+ p = hscx->bch.tx_skb->data + hscx->bch.tx_idx;
+
+ more = test_bit(FLG_TRANSPARENT, &hscx->bch.Flags) ? 1 : 0;
+ if (count > hscx->fifo_size) {
+ count = hscx->fifo_size;
+ more = 1;
+ }
+ pr_debug("%s: B%1d %d/%d/%d\n", hscx->ip->name, hscx->bch.nr, count,
+ hscx->bch.tx_idx, hscx->bch.tx_skb->len);
+ hscx->bch.tx_idx += count;
+
+ if (hscx->ip->type & IPAC_TYPE_IPACX)
+ hscx->ip->write_fifo(hscx->ip->hw,
+ hscx->off + IPACX_XFIFOB, p, count);
+ else {
+ waitforXFW(hscx);
+ hscx->ip->write_fifo(hscx->ip->hw,
+ hscx->off, p, count);
+ }
+ hscx_cmdr(hscx, more ? 0x08 : 0x0a);
+
+ if (hscx->bch.debug & DEBUG_HW_BFIFO) {
+ snprintf(hscx->log, 64, "B%1d-send %s %d ",
+ hscx->bch.nr, hscx->ip->name, count);
+ print_hex_dump_bytes(hscx->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+hscx_xpr(struct hscx_hw *hx)
+{
+ if (hx->bch.tx_skb && hx->bch.tx_idx < hx->bch.tx_skb->len)
+ hscx_fill_fifo(hx);
+ else {
+ if (hx->bch.tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags))
+ confirm_Bsend(&hx->bch);
+ dev_kfree_skb(hx->bch.tx_skb);
+ }
+ if (get_next_bframe(&hx->bch))
+ hscx_fill_fifo(hx);
+ }
+}
+
+static void
+ipac_rme(struct hscx_hw *hx)
+{
+ int count;
+ u8 rstab;
+
+ if (hx->ip->type & IPAC_TYPE_IPACX)
+ rstab = ReadHSCX(hx, IPACX_RSTAB);
+ else
+ rstab = ReadHSCX(hx, IPAC_RSTAB);
+ pr_debug("%s: B%1d RSTAB %02x\n", hx->ip->name, hx->bch.nr, rstab);
+ if ((rstab & 0xf0) != 0xa0) {
+ /* !(VFR && !RDO && CRC && !RAB) */
+ if (!(rstab & 0x80)) {
+ if (hx->bch.debug & DEBUG_HW_BCHANNEL)
+ pr_notice("%s: B%1d invalid frame\n",
+ hx->ip->name, hx->bch.nr);
+ }
+ if (rstab & 0x40) {
+ if (hx->bch.debug & DEBUG_HW_BCHANNEL)
+ pr_notice("%s: B%1d RDO proto=%x\n",
+ hx->ip->name, hx->bch.nr,
+ hx->bch.state);
+ }
+ if (!(rstab & 0x20)) {
+ if (hx->bch.debug & DEBUG_HW_BCHANNEL)
+ pr_notice("%s: B%1d CRC error\n",
+ hx->ip->name, hx->bch.nr);
+ }
+ hscx_cmdr(hx, 0x80); /* Do RMC */
+ return;
+ }
+ if (hx->ip->type & IPAC_TYPE_IPACX)
+ count = ReadHSCX(hx, IPACX_RBCLB);
+ else
+ count = ReadHSCX(hx, IPAC_RBCLB);
+ count &= (hx->fifo_size - 1);
+ if (count == 0)
+ count = hx->fifo_size;
+ hscx_empty_fifo(hx, count);
+ if (!hx->bch.rx_skb)
+ return;
+ if (hx->bch.rx_skb->len < 2) {
+ pr_debug("%s: B%1d frame to short %d\n",
+ hx->ip->name, hx->bch.nr, hx->bch.rx_skb->len);
+ skb_trim(hx->bch.rx_skb, 0);
+ } else {
+ skb_trim(hx->bch.rx_skb, hx->bch.rx_skb->len - 1);
+ recv_Bchannel(&hx->bch, 0);
+ }
+}
+
+static void
+ipac_irq(struct hscx_hw *hx, u8 ista)
+{
+ u8 istab, m, exirb = 0;
+
+ if (hx->ip->type & IPAC_TYPE_IPACX)
+ istab = ReadHSCX(hx, IPACX_ISTAB);
+ else if (hx->ip->type & IPAC_TYPE_IPAC) {
+ istab = ReadHSCX(hx, IPAC_ISTAB);
+ m = (hx->bch.nr & 1) ? IPAC__EXA : IPAC__EXB;
+ if (m & ista) {
+ exirb = ReadHSCX(hx, IPAC_EXIRB);
+ pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
+ hx->bch.nr, exirb);
+ }
+ } else if (hx->bch.nr & 2) { /* HSCX B */
+ if (ista & (HSCX__EXA | HSCX__ICA))
+ ipac_irq(&hx->ip->hscx[0], ista);
+ if (ista & HSCX__EXB) {
+ exirb = ReadHSCX(hx, IPAC_EXIRB);
+ pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
+ hx->bch.nr, exirb);
+ }
+ istab = ista & 0xF8;
+ } else { /* HSCX A */
+ istab = ReadHSCX(hx, IPAC_ISTAB);
+ if (ista & HSCX__EXA) {
+ exirb = ReadHSCX(hx, IPAC_EXIRB);
+ pr_debug("%s: B%1d EXIRB %02x\n", hx->ip->name,
+ hx->bch.nr, exirb);
+ }
+ istab = istab & 0xF8;
+ }
+ if (exirb & IPAC_B_XDU)
+ istab |= IPACX_B_XDU;
+ if (exirb & IPAC_B_RFO)
+ istab |= IPACX_B_RFO;
+ pr_debug("%s: B%1d ISTAB %02x\n", hx->ip->name, hx->bch.nr, istab);
+
+ if (!test_bit(FLG_ACTIVE, &hx->bch.Flags))
+ return;
+
+ if (istab & IPACX_B_RME)
+ ipac_rme(hx);
+
+ if (istab & IPACX_B_RPF) {
+ hscx_empty_fifo(hx, hx->fifo_size);
+ if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
+ /* receive transparent audio data */
+ if (hx->bch.rx_skb)
+ recv_Bchannel(&hx->bch, 0);
+ }
+ }
+
+ if (istab & IPACX_B_RFO) {
+ pr_debug("%s: B%1d RFO error\n", hx->ip->name, hx->bch.nr);
+ hscx_cmdr(hx, 0x40); /* RRES */
+ }
+
+ if (istab & IPACX_B_XPR)
+ hscx_xpr(hx);
+
+ if (istab & IPACX_B_XDU) {
+ if (test_bit(FLG_TRANSPARENT, &hx->bch.Flags)) {
+ hscx_fill_fifo(hx);
+ return;
+ }
+ pr_debug("%s: B%1d XDU error at len %d\n", hx->ip->name,
+ hx->bch.nr, hx->bch.tx_idx);
+ hx->bch.tx_idx = 0;
+ hscx_cmdr(hx, 0x01); /* XRES */
+ }
+}
+
+irqreturn_t
+mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
+{
+ int cnt = maxloop + 1;
+ u8 ista, istad;
+ struct isac_hw *isac = &ipac->isac;
+
+ if (ipac->type & IPAC_TYPE_IPACX) {
+ ista = ReadIPAC(ipac, ISACX_ISTA);
+ while (ista && cnt--) {
+ pr_debug("%s: ISTA %02x\n", ipac->name, ista);
+ if (ista & IPACX__ICA)
+ ipac_irq(&ipac->hscx[0], ista);
+ if (ista & IPACX__ICB)
+ ipac_irq(&ipac->hscx[1], ista);
+ if (ista & (ISACX__ICD | ISACX__CIC))
+ mISDNisac_irq(&ipac->isac, ista);
+ ista = ReadIPAC(ipac, ISACX_ISTA);
+ }
+ } else if (ipac->type & IPAC_TYPE_IPAC) {
+ ista = ReadIPAC(ipac, IPAC_ISTA);
+ while (ista && cnt--) {
+ pr_debug("%s: ISTA %02x\n", ipac->name, ista);
+ if (ista & (IPAC__ICD | IPAC__EXD)) {
+ istad = ReadISAC(isac, ISAC_ISTA);
+ pr_debug("%s: ISTAD %02x\n", ipac->name, istad);
+ if (istad & IPAC_D_TIN2)
+ pr_debug("%s TIN2 irq\n", ipac->name);
+ if (ista & IPAC__EXD)
+ istad |= 1; /* ISAC EXI */
+ mISDNisac_irq(isac, istad);
+ }
+ if (ista & (IPAC__ICA | IPAC__EXA))
+ ipac_irq(&ipac->hscx[0], ista);
+ if (ista & (IPAC__ICB | IPAC__EXB))
+ ipac_irq(&ipac->hscx[1], ista);
+ ista = ReadIPAC(ipac, IPAC_ISTA);
+ }
+ } else if (ipac->type & IPAC_TYPE_HSCX) {
+ while (cnt) {
+ ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off);
+ pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista);
+ if (ista)
+ ipac_irq(&ipac->hscx[1], ista);
+ istad = ReadISAC(isac, ISAC_ISTA);
+ pr_debug("%s: ISTAD %02x\n", ipac->name, istad);
+ if (istad)
+ mISDNisac_irq(isac, istad);
+ if (0 == (ista | istad))
+ break;
+ cnt--;
+ }
+ }
+ if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */
+ return IRQ_NONE;
+ if (cnt < maxloop)
+ pr_debug("%s: %d irqloops cpu%d\n", ipac->name,
+ maxloop - cnt, smp_processor_id());
+ if (maxloop && !cnt)
+ pr_notice("%s: %d IRQ LOOP cpu%d\n", ipac->name,
+ maxloop, smp_processor_id());
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(mISDNipac_irq);
+
+static int
+hscx_mode(struct hscx_hw *hscx, u32 bprotocol)
+{
+ pr_debug("%s: HSCX %c protocol %x-->%x ch %d\n", hscx->ip->name,
+ '@' + hscx->bch.nr, hscx->bch.state, bprotocol, hscx->bch.nr);
+ if (hscx->ip->type & IPAC_TYPE_IPACX) {
+ if (hscx->bch.nr & 1) { /* B1 and ICA */
+ WriteIPAC(hscx->ip, ISACX_BCHA_TSDP_BC1, 0x80);
+ WriteIPAC(hscx->ip, ISACX_BCHA_CR, 0x88);
+ } else { /* B2 and ICB */
+ WriteIPAC(hscx->ip, ISACX_BCHB_TSDP_BC1, 0x81);
+ WriteIPAC(hscx->ip, ISACX_BCHB_CR, 0x88);
+ }
+ switch (bprotocol) {
+ case ISDN_P_NONE: /* init */
+ WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* rec off */
+ WriteHSCX(hscx, IPACX_EXMB, 0x30); /* std adj. */
+ WriteHSCX(hscx, IPACX_MASKB, 0xFF); /* ints off */
+ hscx_cmdr(hscx, 0x41);
+ test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ WriteHSCX(hscx, IPACX_MODEB, 0x88); /* ex trans */
+ WriteHSCX(hscx, IPACX_EXMB, 0x00); /* trans */
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);
+ test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ WriteHSCX(hscx, IPACX_MODEB, 0xC0); /* trans */
+ WriteHSCX(hscx, IPACX_EXMB, 0x00); /* hdlc,crc */
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPACX_MASKB, IPACX_B_ON);
+ test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", hscx->ip->name,
+ bprotocol);
+ return -ENOPROTOOPT;
+ }
+ } else if (hscx->ip->type & IPAC_TYPE_IPAC) { /* IPAC */
+ WriteHSCX(hscx, IPAC_CCR1, 0x82);
+ WriteHSCX(hscx, IPAC_CCR2, 0x30);
+ WriteHSCX(hscx, IPAC_XCCR, 0x07);
+ WriteHSCX(hscx, IPAC_RCCR, 0x07);
+ WriteHSCX(hscx, IPAC_TSAX, hscx->slot);
+ WriteHSCX(hscx, IPAC_TSAR, hscx->slot);
+ switch (bprotocol) {
+ case ISDN_P_NONE:
+ WriteHSCX(hscx, IPAC_TSAX, 0x1F);
+ WriteHSCX(hscx, IPAC_TSAR, 0x1F);
+ WriteHSCX(hscx, IPAC_MODEB, 0x84);
+ WriteHSCX(hscx, IPAC_CCR1, 0x82);
+ WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */
+ test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */
+ WriteHSCX(hscx, IPAC_CCR1, 0x82);
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPAC_MASKB, 0);
+ test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ WriteHSCX(hscx, IPAC_MODEB, 0x8c);
+ WriteHSCX(hscx, IPAC_CCR1, 0x8a);
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPAC_MASKB, 0);
+ test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", hscx->ip->name,
+ bprotocol);
+ return -ENOPROTOOPT;
+ }
+ } else if (hscx->ip->type & IPAC_TYPE_HSCX) { /* HSCX */
+ WriteHSCX(hscx, IPAC_CCR1, 0x85);
+ WriteHSCX(hscx, IPAC_CCR2, 0x30);
+ WriteHSCX(hscx, IPAC_XCCR, 0x07);
+ WriteHSCX(hscx, IPAC_RCCR, 0x07);
+ WriteHSCX(hscx, IPAC_TSAX, hscx->slot);
+ WriteHSCX(hscx, IPAC_TSAR, hscx->slot);
+ switch (bprotocol) {
+ case ISDN_P_NONE:
+ WriteHSCX(hscx, IPAC_TSAX, 0x1F);
+ WriteHSCX(hscx, IPAC_TSAR, 0x1F);
+ WriteHSCX(hscx, IPAC_MODEB, 0x84);
+ WriteHSCX(hscx, IPAC_CCR1, 0x85);
+ WriteHSCX(hscx, IPAC_MASKB, 0xFF); /* ints off */
+ test_and_clear_bit(FLG_HDLC, &hscx->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ WriteHSCX(hscx, IPAC_MODEB, 0xe4); /* ex trans */
+ WriteHSCX(hscx, IPAC_CCR1, 0x85);
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPAC_MASKB, 0);
+ test_and_set_bit(FLG_TRANSPARENT, &hscx->bch.Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ WriteHSCX(hscx, IPAC_MODEB, 0x8c);
+ WriteHSCX(hscx, IPAC_CCR1, 0x8d);
+ hscx_cmdr(hscx, 0x41);
+ WriteHSCX(hscx, IPAC_MASKB, 0);
+ test_and_set_bit(FLG_HDLC, &hscx->bch.Flags);
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", hscx->ip->name,
+ bprotocol);
+ return -ENOPROTOOPT;
+ }
+ } else
+ return -EINVAL;
+ hscx->bch.state = bprotocol;
+ return 0;
+}
+
+static int
+hscx_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ ret = 0;
+ hscx_fill_fifo(hx);
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = hscx_mode(hx, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ mISDN_clear_bchannel(bch);
+ hscx_mode(hx, ISDN_P_NONE);
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x,%x)\n",
+ hx->ip->name, __func__, hh->prim, hh->id);
+ ret = -EINVAL;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: unknown Op %x\n", __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+hscx_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct hscx_hw *hx = container_of(bch, struct hscx_hw, bch);
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", hx->ip->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(hx->ip->hwlock, flags);
+ mISDN_freebchannel(bch);
+ hscx_mode(hx, ISDN_P_NONE);
+ spin_unlock_irqrestore(hx->ip->hwlock, flags);
+ } else {
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(hx->ip->owner);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n",
+ hx->ip->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static void
+free_ipac(struct ipac_hw *ipac)
+{
+ isac_release(&ipac->isac);
+}
+
+static const char *HSCXVer[] =
+{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
+ "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
+
+
+
+static void
+hscx_init(struct hscx_hw *hx)
+{
+ u8 val;
+
+ WriteHSCX(hx, IPAC_RAH2, 0xFF);
+ WriteHSCX(hx, IPAC_XBCH, 0x00);
+ WriteHSCX(hx, IPAC_RLCR, 0x00);
+
+ if (hx->ip->type & IPAC_TYPE_HSCX) {
+ WriteHSCX(hx, IPAC_CCR1, 0x85);
+ val = ReadHSCX(hx, HSCX_VSTR);
+ pr_debug("%s: HSCX VSTR %02x\n", hx->ip->name, val);
+ if (hx->bch.debug & DEBUG_HW)
+ pr_notice("%s: HSCX version %s\n", hx->ip->name,
+ HSCXVer[val & 0x0f]);
+ } else
+ WriteHSCX(hx, IPAC_CCR1, 0x82);
+ WriteHSCX(hx, IPAC_CCR2, 0x30);
+ WriteHSCX(hx, IPAC_XCCR, 0x07);
+ WriteHSCX(hx, IPAC_RCCR, 0x07);
+}
+
+static int
+ipac_init(struct ipac_hw *ipac)
+{
+ u8 val;
+
+ if (ipac->type & IPAC_TYPE_HSCX) {
+ hscx_init(&ipac->hscx[0]);
+ hscx_init(&ipac->hscx[1]);
+ val = ReadIPAC(ipac, IPAC_ID);
+ } else if (ipac->type & IPAC_TYPE_IPAC) {
+ hscx_init(&ipac->hscx[0]);
+ hscx_init(&ipac->hscx[1]);
+ WriteIPAC(ipac, IPAC_MASK, IPAC__ON);
+ val = ReadIPAC(ipac, IPAC_CONF);
+ /* conf is default 0, but can be overwritten by card setup */
+ pr_debug("%s: IPAC CONF %02x/%02x\n", ipac->name,
+ val, ipac->conf);
+ WriteIPAC(ipac, IPAC_CONF, ipac->conf);
+ val = ReadIPAC(ipac, IPAC_ID);
+ if (ipac->hscx[0].bch.debug & DEBUG_HW)
+ pr_notice("%s: IPAC Design ID %02x\n", ipac->name, val);
+ }
+ /* nothing special for IPACX to do here */
+ return isac_init(&ipac->isac);
+}
+
+static int
+open_bchannel(struct ipac_hw *ipac, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &ipac->hscx[rq->adr.channel - 1].bch;
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+static int
+channel_ctrl(struct ipac_hw *ipac, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP;
+ break;
+ case MISDN_CTRL_LOOP:
+ /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+ if (cq->channel < 0 || cq->channel > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = ipac->ctrl(ipac, HW_TESTLOOP, cq->channel);
+ break;
+ default:
+ pr_info("%s: unknown CTRL OP %x\n", ipac->name, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct isac_hw *isac = container_of(dch, struct isac_hw, dch);
+ struct ipac_hw *ipac = container_of(isac, struct ipac_hw, isac);
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: DCTRL: %x %p\n", ipac->name, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = open_dchannel(isac, rq);
+ else
+ err = open_bchannel(ipac, rq);
+ if (err)
+ break;
+ if (!try_module_get(ipac->owner))
+ pr_info("%s: cannot get module\n", ipac->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", ipac->name,
+ dch->dev.id, __builtin_return_address(0));
+ module_put(ipac->owner);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(ipac, arg);
+ break;
+ default:
+ pr_debug("%s: unknown DCTRL command %x\n", ipac->name, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+u32
+mISDNipac_init(struct ipac_hw *ipac, void *hw)
+{
+ u32 ret;
+ u8 i;
+
+ ipac->hw = hw;
+ if (ipac->isac.dch.debug & DEBUG_HW)
+ pr_notice("%s: ipac type %x\n", ipac->name, ipac->type);
+ if (ipac->type & IPAC_TYPE_HSCX) {
+ ipac->isac.type = IPAC_TYPE_ISAC;
+ ipac->hscx[0].off = 0;
+ ipac->hscx[1].off = 0x40;
+ ipac->hscx[0].fifo_size = 32;
+ ipac->hscx[1].fifo_size = 32;
+ } else if (ipac->type & IPAC_TYPE_IPAC) {
+ ipac->isac.type = IPAC_TYPE_IPAC | IPAC_TYPE_ISAC;
+ ipac->hscx[0].off = 0;
+ ipac->hscx[1].off = 0x40;
+ ipac->hscx[0].fifo_size = 64;
+ ipac->hscx[1].fifo_size = 64;
+ } else if (ipac->type & IPAC_TYPE_IPACX) {
+ ipac->isac.type = IPAC_TYPE_IPACX | IPAC_TYPE_ISACX;
+ ipac->hscx[0].off = IPACX_OFF_ICA;
+ ipac->hscx[1].off = IPACX_OFF_ICB;
+ ipac->hscx[0].fifo_size = 64;
+ ipac->hscx[1].fifo_size = 64;
+ } else
+ return 0;
+
+ mISDNisac_init(&ipac->isac, hw);
+
+ ipac->isac.dch.dev.D.ctrl = ipac_dctrl;
+
+ for (i = 0; i < 2; i++) {
+ ipac->hscx[i].bch.nr = i + 1;
+ set_channelmap(i + 1, ipac->isac.dch.dev.channelmap);
+ list_add(&ipac->hscx[i].bch.ch.list,
+ &ipac->isac.dch.dev.bchannels);
+ mISDN_initbchannel(&ipac->hscx[i].bch, MAX_DATA_MEM);
+ ipac->hscx[i].bch.ch.nr = i + 1;
+ ipac->hscx[i].bch.ch.send = &hscx_l2l1;
+ ipac->hscx[i].bch.ch.ctrl = hscx_bctrl;
+ ipac->hscx[i].bch.hw = hw;
+ ipac->hscx[i].ip = ipac;
+ /* default values for IOM time slots
+ * can be overwriten by card */
+ ipac->hscx[i].slot = (i == 0) ? 0x2f : 0x03;
+ }
+
+ ipac->init = ipac_init;
+ ipac->release = free_ipac;
+
+ ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ return ret;
+}
+EXPORT_SYMBOL(mISDNipac_init);
+
+static int __init
+isac_mod_init(void)
+{
+ pr_notice("mISDNipac module version %s\n", ISAC_REV);
+ return 0;
+}
+
+static void __exit
+isac_mod_cleanup(void)
+{
+ pr_notice("mISDNipac module unloaded\n");
+}
+module_init(isac_mod_init);
+module_exit(isac_mod_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/mISDNisar.c b/drivers/isdn/hardware/mISDN/mISDNisar.c
new file mode 100644
index 00000000000..de352a17673
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/mISDNisar.c
@@ -0,0 +1,1726 @@
+/*
+ * mISDNisar.c ISAR (Siemens PSB 7110) specific functions
+ *
+ * Author Karsten Keil (keil@isdn4linux.de)
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* define this to enable static debug messages, if you kernel supports
+ * dynamic debugging, you should use debugfs for this
+ */
+/* #define DEBUG */
+
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/mISDNhw.h>
+#include "isar.h"
+
+#define ISAR_REV "2.1"
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ISAR_REV);
+
+#define DEBUG_HW_FIRMWARE_FIFO 0x10000
+
+static const u8 faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146";
+static const u8 faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121,
+ 122, 145, 146};
+#define FAXMODCNT 13
+
+static void isar_setup(struct isar_hw *);
+
+static inline int
+waitforHIA(struct isar_hw *isar, int timeout)
+{
+ int t = timeout;
+ u8 val = isar->read_reg(isar->hw, ISAR_HIA);
+
+ while ((val & 1) && t) {
+ udelay(1);
+ t--;
+ val = isar->read_reg(isar->hw, ISAR_HIA);
+ }
+ pr_debug("%s: HIA after %dus\n", isar->name, timeout - t);
+ return timeout;
+}
+
+/*
+ * send msg to ISAR mailbox
+ * if msg is NULL use isar->buf
+ */
+static int
+send_mbox(struct isar_hw *isar, u8 his, u8 creg, u8 len, u8 *msg)
+{
+ if (!waitforHIA(isar, 1000))
+ return 0;
+ pr_debug("send_mbox(%02x,%02x,%d)\n", his, creg, len);
+ isar->write_reg(isar->hw, ISAR_CTRL_H, creg);
+ isar->write_reg(isar->hw, ISAR_CTRL_L, len);
+ isar->write_reg(isar->hw, ISAR_WADR, 0);
+ if (!msg)
+ msg = isar->buf;
+ if (msg && len) {
+ isar->write_fifo(isar->hw, ISAR_MBOX, msg, len);
+ if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) {
+ int l = 0;
+
+ while (l < (int)len) {
+ hex_dump_to_buffer(msg + l, len - l, 32, 1,
+ isar->log, 256, 1);
+ pr_debug("%s: %s %02x: %s\n", isar->name,
+ __func__, l, isar->log);
+ l += 32;
+ }
+ }
+ }
+ isar->write_reg(isar->hw, ISAR_HIS, his);
+ waitforHIA(isar, 1000);
+ return 1;
+}
+
+/*
+ * receive message from ISAR mailbox
+ * if msg is NULL use isar->buf
+ */
+static void
+rcv_mbox(struct isar_hw *isar, u8 *msg)
+{
+ if (!msg)
+ msg = isar->buf;
+ isar->write_reg(isar->hw, ISAR_RADR, 0);
+ if (msg && isar->clsb) {
+ isar->read_fifo(isar->hw, ISAR_MBOX, msg, isar->clsb);
+ if (isar->ch[0].bch.debug & DEBUG_HW_BFIFO) {
+ int l = 0;
+
+ while (l < (int)isar->clsb) {
+ hex_dump_to_buffer(msg + l, isar->clsb - l, 32,
+ 1, isar->log, 256, 1);
+ pr_debug("%s: %s %02x: %s\n", isar->name,
+ __func__, l, isar->log);
+ l += 32;
+ }
+ }
+ }
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+}
+
+static inline void
+get_irq_infos(struct isar_hw *isar)
+{
+ isar->iis = isar->read_reg(isar->hw, ISAR_IIS);
+ isar->cmsb = isar->read_reg(isar->hw, ISAR_CTRL_H);
+ isar->clsb = isar->read_reg(isar->hw, ISAR_CTRL_L);
+ pr_debug("%s: rcv_mbox(%02x,%02x,%d)\n", isar->name,
+ isar->iis, isar->cmsb, isar->clsb);
+}
+
+/*
+ * poll answer message from ISAR mailbox
+ * should be used only with ISAR IRQs disabled before DSP was started
+ *
+ */
+static int
+poll_mbox(struct isar_hw *isar, int maxdelay)
+{
+ int t = maxdelay;
+ u8 irq;
+
+ irq = isar->read_reg(isar->hw, ISAR_IRQBIT);
+ while (t && !(irq & ISAR_IRQSTA)) {
+ udelay(1);
+ t--;
+ }
+ if (t) {
+ get_irq_infos(isar);
+ rcv_mbox(isar, NULL);
+ }
+ pr_debug("%s: pulled %d bytes after %d us\n",
+ isar->name, isar->clsb, maxdelay - t);
+ return t;
+}
+
+static int
+ISARVersion(struct isar_hw *isar)
+{
+ int ver;
+
+ /* disable ISAR IRQ */
+ isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
+ isar->buf[0] = ISAR_MSG_HWVER;
+ isar->buf[1] = 0;
+ isar->buf[2] = 1;
+ if (!send_mbox(isar, ISAR_HIS_VNR, 0, 3, NULL))
+ return -1;
+ if (!poll_mbox(isar, 1000))
+ return -2;
+ if (isar->iis == ISAR_IIS_VNR) {
+ if (isar->clsb == 1) {
+ ver = isar->buf[0] & 0xf;
+ return ver;
+ }
+ return -3;
+ }
+ return -4;
+}
+
+static int
+load_firmware(struct isar_hw *isar, const u8 *buf, int size)
+{
+ u32 saved_debug = isar->ch[0].bch.debug;
+ int ret, cnt;
+ u8 nom, noc;
+ u16 left, val, *sp = (u16 *)buf;
+ u8 *mp;
+ u_long flags;
+
+ struct {
+ u16 sadr;
+ u16 len;
+ u16 d_key;
+ } blk_head;
+
+ if (1 != isar->version) {
+ pr_err("%s: ISAR wrong version %d firmware download aborted\n",
+ isar->name, isar->version);
+ return -EINVAL;
+ }
+ if (!(saved_debug & DEBUG_HW_FIRMWARE_FIFO))
+ isar->ch[0].bch.debug &= ~DEBUG_HW_BFIFO;
+ pr_debug("%s: load firmware %d words (%d bytes)\n",
+ isar->name, size/2, size);
+ cnt = 0;
+ size /= 2;
+ /* disable ISAR IRQ */
+ spin_lock_irqsave(isar->hwlock, flags);
+ isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ while (cnt < size) {
+ blk_head.sadr = le16_to_cpu(*sp++);
+ blk_head.len = le16_to_cpu(*sp++);
+ blk_head.d_key = le16_to_cpu(*sp++);
+ cnt += 3;
+ pr_debug("ISAR firmware block (%#x,%d,%#x)\n",
+ blk_head.sadr, blk_head.len, blk_head.d_key & 0xff);
+ left = blk_head.len;
+ if (cnt + left > size) {
+ pr_info("%s: firmware error have %d need %d words\n",
+ isar->name, size, cnt + left);
+ ret = -EINVAL;
+ goto reterrflg;
+ }
+ spin_lock_irqsave(isar->hwlock, flags);
+ if (!send_mbox(isar, ISAR_HIS_DKEY, blk_head.d_key & 0xff,
+ 0, NULL)) {
+ pr_info("ISAR send_mbox dkey failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ if (!poll_mbox(isar, 1000)) {
+ pr_warning("ISAR poll_mbox dkey failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ if ((isar->iis != ISAR_IIS_DKEY) || isar->cmsb || isar->clsb) {
+ pr_info("ISAR wrong dkey response (%x,%x,%x)\n",
+ isar->iis, isar->cmsb, isar->clsb);
+ ret = 1;
+ goto reterrflg;
+ }
+ while (left > 0) {
+ if (left > 126)
+ noc = 126;
+ else
+ noc = left;
+ nom = (2 * noc) + 3;
+ mp = isar->buf;
+ /* the ISAR is big endian */
+ *mp++ = blk_head.sadr >> 8;
+ *mp++ = blk_head.sadr & 0xFF;
+ left -= noc;
+ cnt += noc;
+ *mp++ = noc;
+ pr_debug("%s: load %3d words at %04x\n", isar->name,
+ noc, blk_head.sadr);
+ blk_head.sadr += noc;
+ while (noc) {
+ val = le16_to_cpu(*sp++);
+ *mp++ = val >> 8;
+ *mp++ = val & 0xFF;;
+ noc--;
+ }
+ spin_lock_irqsave(isar->hwlock, flags);
+ if (!send_mbox(isar, ISAR_HIS_FIRM, 0, nom, NULL)) {
+ pr_info("ISAR send_mbox prog failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ if (!poll_mbox(isar, 1000)) {
+ pr_info("ISAR poll_mbox prog failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ if ((isar->iis != ISAR_IIS_FIRM) ||
+ isar->cmsb || isar->clsb) {
+ pr_info("ISAR wrong prog response (%x,%x,%x)\n",
+ isar->iis, isar->cmsb, isar->clsb);
+ ret = -EIO;
+ goto reterrflg;
+ }
+ }
+ pr_debug("%s: ISAR firmware block %d words loaded\n",
+ isar->name, blk_head.len);
+ }
+ isar->ch[0].bch.debug = saved_debug;
+ /* 10ms delay */
+ cnt = 10;
+ while (cnt--)
+ mdelay(1);
+ isar->buf[0] = 0xff;
+ isar->buf[1] = 0xfe;
+ isar->bstat = 0;
+ spin_lock_irqsave(isar->hwlock, flags);
+ if (!send_mbox(isar, ISAR_HIS_STDSP, 0, 2, NULL)) {
+ pr_info("ISAR send_mbox start dsp failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ if (!poll_mbox(isar, 1000)) {
+ pr_info("ISAR poll_mbox start dsp failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ if ((isar->iis != ISAR_IIS_STDSP) || isar->cmsb || isar->clsb) {
+ pr_info("ISAR wrong start dsp response (%x,%x,%x)\n",
+ isar->iis, isar->cmsb, isar->clsb);
+ ret = -EIO;
+ goto reterror;
+ } else
+ pr_debug("%s: ISAR start dsp success\n", isar->name);
+
+ /* NORMAL mode entered */
+ /* Enable IRQs of ISAR */
+ isar->write_reg(isar->hw, ISAR_IRQBIT, ISAR_IRQSTA);
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ cnt = 1000; /* max 1s */
+ while ((!isar->bstat) && cnt) {
+ mdelay(1);
+ cnt--;
+ }
+ if (!cnt) {
+ pr_info("ISAR no general status event received\n");
+ ret = -ETIME;
+ goto reterrflg;
+ } else
+ pr_debug("%s: ISAR general status event %x\n",
+ isar->name, isar->bstat);
+ /* 10ms delay */
+ cnt = 10;
+ while (cnt--)
+ mdelay(1);
+ isar->iis = 0;
+ spin_lock_irqsave(isar->hwlock, flags);
+ if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) {
+ pr_info("ISAR send_mbox self tst failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ cnt = 10000; /* max 100 ms */
+ while ((isar->iis != ISAR_IIS_DIAG) && cnt) {
+ udelay(10);
+ cnt--;
+ }
+ mdelay(1);
+ if (!cnt) {
+ pr_info("ISAR no self tst response\n");
+ ret = -ETIME;
+ goto reterrflg;
+ }
+ if ((isar->cmsb == ISAR_CTRL_STST) && (isar->clsb == 1)
+ && (isar->buf[0] == 0))
+ pr_debug("%s: ISAR selftest OK\n", isar->name);
+ else {
+ pr_info("ISAR selftest not OK %x/%x/%x\n",
+ isar->cmsb, isar->clsb, isar->buf[0]);
+ ret = -EIO;
+ goto reterrflg;
+ }
+ spin_lock_irqsave(isar->hwlock, flags);
+ isar->iis = 0;
+ if (!send_mbox(isar, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) {
+ pr_info("ISAR RQST SVN failed\n");
+ ret = -ETIME;
+ goto reterror;
+ }
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ cnt = 30000; /* max 300 ms */
+ while ((isar->iis != ISAR_IIS_DIAG) && cnt) {
+ udelay(10);
+ cnt--;
+ }
+ mdelay(1);
+ if (!cnt) {
+ pr_info("ISAR no SVN response\n");
+ ret = -ETIME;
+ goto reterrflg;
+ } else {
+ if ((isar->cmsb == ISAR_CTRL_SWVER) && (isar->clsb == 1)) {
+ pr_notice("%s: ISAR software version %#x\n",
+ isar->name, isar->buf[0]);
+ } else {
+ pr_info("%s: ISAR wrong swver response (%x,%x)"
+ " cnt(%d)\n", isar->name, isar->cmsb,
+ isar->clsb, cnt);
+ ret = -EIO;
+ goto reterrflg;
+ }
+ }
+ spin_lock_irqsave(isar->hwlock, flags);
+ isar_setup(isar);
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ ret = 0;
+reterrflg:
+ spin_lock_irqsave(isar->hwlock, flags);
+reterror:
+ isar->ch[0].bch.debug = saved_debug;
+ if (ret)
+ /* disable ISAR IRQ */
+ isar->write_reg(isar->hw, ISAR_IRQBIT, 0);
+ spin_unlock_irqrestore(isar->hwlock, flags);
+ return ret;
+}
+
+static inline void
+deliver_status(struct isar_ch *ch, int status)
+{
+ pr_debug("%s: HL->LL FAXIND %x\n", ch->is->name, status);
+ _queue_data(&ch->bch.ch, PH_CONTROL_IND, status, 0, NULL, GFP_ATOMIC);
+}
+
+static inline void
+isar_rcv_frame(struct isar_ch *ch)
+{
+ u8 *ptr;
+
+ if (!ch->is->clsb) {
+ pr_debug("%s; ISAR zero len frame\n", ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ return;
+ }
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ pr_debug("%s: ISAR protocol 0 spurious IIS_RDATA %x/%x/%x\n",
+ ch->is->name, ch->is->iis, ch->is->cmsb, ch->is->clsb);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_L2DTMF:
+ case ISDN_P_B_MODEM_ASYNC:
+ if (!ch->bch.rx_skb) {
+ ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
+ GFP_ATOMIC);
+ if (unlikely(!ch->bch.rx_skb)) {
+ pr_info("%s: B receive out of memory\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ }
+ rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
+ recv_Bchannel(&ch->bch, 0);
+ break;
+ case ISDN_P_B_HDLC:
+ if (!ch->bch.rx_skb) {
+ ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
+ GFP_ATOMIC);
+ if (unlikely(!ch->bch.rx_skb)) {
+ pr_info("%s: B receive out of memory\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ }
+ if ((ch->bch.rx_skb->len + ch->is->clsb) >
+ (ch->bch.maxlen + 2)) {
+ pr_debug("%s: incoming packet too large\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ if (ch->is->cmsb & HDLC_ERROR) {
+ pr_debug("%s: ISAR frame error %x len %d\n",
+ ch->is->name, ch->is->cmsb, ch->is->clsb);
+#ifdef ERROR_STATISTIC
+ if (ch->is->cmsb & HDLC_ERR_RER)
+ ch->bch.err_inv++;
+ if (ch->is->cmsb & HDLC_ERR_CER)
+ ch->bch.err_crc++;
+#endif
+ skb_trim(ch->bch.rx_skb, 0);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ if (ch->is->cmsb & HDLC_FSD)
+ skb_trim(ch->bch.rx_skb, 0);
+ ptr = skb_put(ch->bch.rx_skb, ch->is->clsb);
+ rcv_mbox(ch->is, ptr);
+ if (ch->is->cmsb & HDLC_FED) {
+ if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */
+ pr_debug("%s: ISAR frame to short %d\n",
+ ch->is->name, ch->bch.rx_skb->len);
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2);
+ recv_Bchannel(&ch->bch, 0);
+ }
+ break;
+ case ISDN_P_B_T30_FAX:
+ if (ch->state != STFAX_ACTIV) {
+ pr_debug("%s: isar_rcv_frame: not ACTIV\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ if (ch->bch.rx_skb)
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ if (!ch->bch.rx_skb) {
+ ch->bch.rx_skb = mI_alloc_skb(ch->bch.maxlen,
+ GFP_ATOMIC);
+ if (unlikely(!ch->bch.rx_skb)) {
+ pr_info("%s: B receive out of memory\n",
+ __func__);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ }
+ if (ch->cmd == PCTRL_CMD_FRM) {
+ rcv_mbox(ch->is, skb_put(ch->bch.rx_skb, ch->is->clsb));
+ pr_debug("%s: isar_rcv_frame: %d\n",
+ ch->is->name, ch->bch.rx_skb->len);
+ if (ch->is->cmsb & SART_NMD) { /* ABORT */
+ pr_debug("%s: isar_rcv_frame: no more data\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ send_mbox(ch->is, SET_DPS(ch->dpath) |
+ ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
+ 0, NULL);
+ ch->state = STFAX_ESCAPE;
+ /* set_skb_flag(skb, DF_NOMOREDATA); */
+ }
+ recv_Bchannel(&ch->bch, 0);
+ if (ch->is->cmsb & SART_NMD)
+ deliver_status(ch, HW_MOD_NOCARR);
+ break;
+ }
+ if (ch->cmd != PCTRL_CMD_FRH) {
+ pr_debug("%s: isar_rcv_frame: unknown fax mode %x\n",
+ ch->is->name, ch->cmd);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ if (ch->bch.rx_skb)
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ /* PCTRL_CMD_FRH */
+ if ((ch->bch.rx_skb->len + ch->is->clsb) >
+ (ch->bch.maxlen + 2)) {
+ pr_info("%s: %s incoming packet too large\n",
+ ch->is->name, __func__);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ } else if (ch->is->cmsb & HDLC_ERROR) {
+ pr_info("%s: ISAR frame error %x len %d\n",
+ ch->is->name, ch->is->cmsb, ch->is->clsb);
+ skb_trim(ch->bch.rx_skb, 0);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+ if (ch->is->cmsb & HDLC_FSD)
+ skb_trim(ch->bch.rx_skb, 0);
+ ptr = skb_put(ch->bch.rx_skb, ch->is->clsb);
+ rcv_mbox(ch->is, ptr);
+ if (ch->is->cmsb & HDLC_FED) {
+ if (ch->bch.rx_skb->len < 3) { /* last 2 are the FCS */
+ pr_info("%s: ISAR frame to short %d\n",
+ ch->is->name, ch->bch.rx_skb->len);
+ skb_trim(ch->bch.rx_skb, 0);
+ break;
+ }
+ skb_trim(ch->bch.rx_skb, ch->bch.rx_skb->len - 2);
+ recv_Bchannel(&ch->bch, 0);
+ }
+ if (ch->is->cmsb & SART_NMD) { /* ABORT */
+ pr_debug("%s: isar_rcv_frame: no more data\n",
+ ch->is->name);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ if (ch->bch.rx_skb)
+ skb_trim(ch->bch.rx_skb, 0);
+ send_mbox(ch->is, SET_DPS(ch->dpath) |
+ ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+ ch->state = STFAX_ESCAPE;
+ deliver_status(ch, HW_MOD_NOCARR);
+ }
+ break;
+ default:
+ pr_info("isar_rcv_frame protocol (%x)error\n", ch->bch.state);
+ ch->is->write_reg(ch->is->hw, ISAR_IIA, 0);
+ break;
+ }
+}
+
+static void
+isar_fill_fifo(struct isar_ch *ch)
+{
+ int count;
+ u8 msb;
+ u8 *ptr;
+
+ pr_debug("%s: ch%d tx_skb %p tx_idx %d\n",
+ ch->is->name, ch->bch.nr, ch->bch.tx_skb, ch->bch.tx_idx);
+ if (!ch->bch.tx_skb)
+ return;
+ count = ch->bch.tx_skb->len - ch->bch.tx_idx;
+ if (count <= 0)
+ return;
+ if (!(ch->is->bstat &
+ (ch->dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2)))
+ return;
+ if (count > ch->mml) {
+ msb = 0;
+ count = ch->mml;
+ } else {
+ msb = HDLC_FED;
+ }
+ ptr = ch->bch.tx_skb->data + ch->bch.tx_idx;
+ if (!ch->bch.tx_idx) {
+ pr_debug("%s: frame start\n", ch->is->name);
+ if ((ch->bch.state == ISDN_P_B_T30_FAX) &&
+ (ch->cmd == PCTRL_CMD_FTH)) {
+ if (count > 1) {
+ if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) {
+ /* last frame */
+ test_and_set_bit(FLG_LASTDATA,
+ &ch->bch.Flags);
+ pr_debug("%s: set LASTDATA\n",
+ ch->is->name);
+ if (msb == HDLC_FED)
+ test_and_set_bit(FLG_DLEETX,
+ &ch->bch.Flags);
+ }
+ }
+ }
+ msb |= HDLC_FST;
+ }
+ ch->bch.tx_idx += count;
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ pr_info("%s: wrong protocol 0\n", __func__);
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_L2DTMF:
+ case ISDN_P_B_MODEM_ASYNC:
+ send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
+ 0, count, ptr);
+ break;
+ case ISDN_P_B_HDLC:
+ send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
+ msb, count, ptr);
+ break;
+ case ISDN_P_B_T30_FAX:
+ if (ch->state != STFAX_ACTIV)
+ pr_debug("%s: not ACTIV\n", ch->is->name);
+ else if (ch->cmd == PCTRL_CMD_FTH)
+ send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
+ msb, count, ptr);
+ else if (ch->cmd == PCTRL_CMD_FTM)
+ send_mbox(ch->is, SET_DPS(ch->dpath) | ISAR_HIS_SDATA,
+ 0, count, ptr);
+ else
+ pr_debug("%s: not FTH/FTM\n", ch->is->name);
+ break;
+ default:
+ pr_info("%s: protocol(%x) error\n",
+ __func__, ch->bch.state);
+ break;
+ }
+}
+
+static inline struct isar_ch *
+sel_bch_isar(struct isar_hw *isar, u8 dpath)
+{
+ struct isar_ch *base = &isar->ch[0];
+
+ if ((!dpath) || (dpath > 2))
+ return NULL;
+ if (base->dpath == dpath)
+ return base;
+ base++;
+ if (base->dpath == dpath)
+ return base;
+ return NULL;
+}
+
+static void
+send_next(struct isar_ch *ch)
+{
+ pr_debug("%s: %s ch%d tx_skb %p tx_idx %d\n",
+ ch->is->name, __func__, ch->bch.nr,
+ ch->bch.tx_skb, ch->bch.tx_idx);
+ if (ch->bch.state == ISDN_P_B_T30_FAX) {
+ if (ch->cmd == PCTRL_CMD_FTH) {
+ if (test_bit(FLG_LASTDATA, &ch->bch.Flags)) {
+ pr_debug("set NMD_DATA\n");
+ test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags);
+ }
+ } else if (ch->cmd == PCTRL_CMD_FTM) {
+ if (test_bit(FLG_DLEETX, &ch->bch.Flags)) {
+ test_and_set_bit(FLG_LASTDATA, &ch->bch.Flags);
+ test_and_set_bit(FLG_NMD_DATA, &ch->bch.Flags);
+ }
+ }
+ }
+ if (ch->bch.tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &ch->bch.Flags))
+ confirm_Bsend(&ch->bch);
+ dev_kfree_skb(ch->bch.tx_skb);
+ }
+ if (get_next_bframe(&ch->bch))
+ isar_fill_fifo(ch);
+ else {
+ if (test_and_clear_bit(FLG_DLEETX, &ch->bch.Flags)) {
+ if (test_and_clear_bit(FLG_LASTDATA,
+ &ch->bch.Flags)) {
+ if (test_and_clear_bit(FLG_NMD_DATA,
+ &ch->bch.Flags)) {
+ u8 zd = 0;
+ send_mbox(ch->is, SET_DPS(ch->dpath) |
+ ISAR_HIS_SDATA, 0x01, 1, &zd);
+ }
+ test_and_set_bit(FLG_LL_OK, &ch->bch.Flags);
+ } else {
+ deliver_status(ch, HW_MOD_CONNECT);
+ }
+ }
+ }
+}
+
+static void
+check_send(struct isar_hw *isar, u8 rdm)
+{
+ struct isar_ch *ch;
+
+ pr_debug("%s: rdm %x\n", isar->name, rdm);
+ if (rdm & BSTAT_RDM1) {
+ ch = sel_bch_isar(isar, 1);
+ if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) {
+ if (ch->bch.tx_skb && (ch->bch.tx_skb->len >
+ ch->bch.tx_idx))
+ isar_fill_fifo(ch);
+ else
+ send_next(ch);
+ }
+ }
+ if (rdm & BSTAT_RDM2) {
+ ch = sel_bch_isar(isar, 2);
+ if (ch && test_bit(FLG_ACTIVE, &ch->bch.Flags)) {
+ if (ch->bch.tx_skb && (ch->bch.tx_skb->len >
+ ch->bch.tx_idx))
+ isar_fill_fifo(ch);
+ else
+ send_next(ch);
+ }
+ }
+}
+
+const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
+ "300", "600", "1200", "2400", "4800", "7200",
+ "9600nt", "9600t", "12000", "14400", "WRONG"};
+const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
+ "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};
+
+static void
+isar_pump_status_rsp(struct isar_ch *ch) {
+ u8 ril = ch->is->buf[0];
+ u8 rim;
+
+ if (!test_and_clear_bit(ISAR_RATE_REQ, &ch->is->Flags))
+ return;
+ if (ril > 14) {
+ pr_info("%s: wrong pstrsp ril=%d\n", ch->is->name, ril);
+ ril = 15;
+ }
+ switch (ch->is->buf[1]) {
+ case 0:
+ rim = 0;
+ break;
+ case 0x20:
+ rim = 2;
+ break;
+ case 0x40:
+ rim = 3;
+ break;
+ case 0x41:
+ rim = 4;
+ break;
+ case 0x51:
+ rim = 5;
+ break;
+ case 0x61:
+ rim = 6;
+ break;
+ case 0x71:
+ rim = 7;
+ break;
+ case 0x82:
+ rim = 8;
+ break;
+ case 0x92:
+ rim = 9;
+ break;
+ case 0xa2:
+ rim = 10;
+ break;
+ default:
+ rim = 1;
+ break;
+ }
+ sprintf(ch->conmsg, "%s %s", dmril[ril], dmrim[rim]);
+ pr_debug("%s: pump strsp %s\n", ch->is->name, ch->conmsg);
+}
+
+static void
+isar_pump_statev_modem(struct isar_ch *ch, u8 devt) {
+ u8 dps = SET_DPS(ch->dpath);
+
+ switch (devt) {
+ case PSEV_10MS_TIMER:
+ pr_debug("%s: pump stev TIMER\n", ch->is->name);
+ break;
+ case PSEV_CON_ON:
+ pr_debug("%s: pump stev CONNECT\n", ch->is->name);
+ deliver_status(ch, HW_MOD_CONNECT);
+ break;
+ case PSEV_CON_OFF:
+ pr_debug("%s: pump stev NO CONNECT\n", ch->is->name);
+ send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ deliver_status(ch, HW_MOD_NOCARR);
+ break;
+ case PSEV_V24_OFF:
+ pr_debug("%s: pump stev V24 OFF\n", ch->is->name);
+ break;
+ case PSEV_CTS_ON:
+ pr_debug("%s: pump stev CTS ON\n", ch->is->name);
+ break;
+ case PSEV_CTS_OFF:
+ pr_debug("%s pump stev CTS OFF\n", ch->is->name);
+ break;
+ case PSEV_DCD_ON:
+ pr_debug("%s: pump stev CARRIER ON\n", ch->is->name);
+ test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags);
+ send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ break;
+ case PSEV_DCD_OFF:
+ pr_debug("%s: pump stev CARRIER OFF\n", ch->is->name);
+ break;
+ case PSEV_DSR_ON:
+ pr_debug("%s: pump stev DSR ON\n", ch->is->name);
+ break;
+ case PSEV_DSR_OFF:
+ pr_debug("%s: pump stev DSR_OFF\n", ch->is->name);
+ break;
+ case PSEV_REM_RET:
+ pr_debug("%s: pump stev REMOTE RETRAIN\n", ch->is->name);
+ break;
+ case PSEV_REM_REN:
+ pr_debug("%s: pump stev REMOTE RENEGOTIATE\n", ch->is->name);
+ break;
+ case PSEV_GSTN_CLR:
+ pr_debug("%s: pump stev GSTN CLEAR\n", ch->is->name);
+ break;
+ default:
+ pr_info("u%s: nknown pump stev %x\n", ch->is->name, devt);
+ break;
+ }
+}
+
+static void
+isar_pump_statev_fax(struct isar_ch *ch, u8 devt) {
+ u8 dps = SET_DPS(ch->dpath);
+ u8 p1;
+
+ switch (devt) {
+ case PSEV_10MS_TIMER:
+ pr_debug("%s: pump stev TIMER\n", ch->is->name);
+ break;
+ case PSEV_RSP_READY:
+ pr_debug("%s: pump stev RSP_READY\n", ch->is->name);
+ ch->state = STFAX_READY;
+ deliver_status(ch, HW_MOD_READY);
+#ifdef AUTOCON
+ if (test_bit(BC_FLG_ORIG, &ch->bch.Flags))
+ isar_pump_cmd(bch, HW_MOD_FRH, 3);
+ else
+ isar_pump_cmd(bch, HW_MOD_FTH, 3);
+#endif
+ break;
+ case PSEV_LINE_TX_H:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev LINE_TX_H\n", ch->is->name);
+ ch->state = STFAX_CONT;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ pr_debug("%s: pump stev LINE_TX_H wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_LINE_RX_H:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev LINE_RX_H\n", ch->is->name);
+ ch->state = STFAX_CONT;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ pr_debug("%s: pump stev LINE_RX_H wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_LINE_TX_B:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev LINE_TX_B\n", ch->is->name);
+ ch->state = STFAX_CONT;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ pr_debug("%s: pump stev LINE_TX_B wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_LINE_RX_B:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev LINE_RX_B\n", ch->is->name);
+ ch->state = STFAX_CONT;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_CONT, 0, NULL);
+ } else {
+ pr_debug("%s: pump stev LINE_RX_B wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_RSP_CONN:
+ if (ch->state == STFAX_CONT) {
+ pr_debug("%s: pump stev RSP_CONN\n", ch->is->name);
+ ch->state = STFAX_ACTIV;
+ test_and_set_bit(ISAR_RATE_REQ, &ch->is->Flags);
+ send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ if (ch->cmd == PCTRL_CMD_FTH) {
+ int delay = (ch->mod == 3) ? 1000 : 200;
+ /* 1s (200 ms) Flags before data */
+ if (test_and_set_bit(FLG_FTI_RUN,
+ &ch->bch.Flags))
+ del_timer(&ch->ftimer);
+ ch->ftimer.expires =
+ jiffies + ((delay * HZ)/1000);
+ test_and_set_bit(FLG_LL_CONN,
+ &ch->bch.Flags);
+ add_timer(&ch->ftimer);
+ } else {
+ deliver_status(ch, HW_MOD_CONNECT);
+ }
+ } else {
+ pr_debug("%s: pump stev RSP_CONN wrong st %x\n",
+ ch->is->name, ch->state);
+ }
+ break;
+ case PSEV_FLAGS_DET:
+ pr_debug("%s: pump stev FLAGS_DET\n", ch->is->name);
+ break;
+ case PSEV_RSP_DISC:
+ pr_debug("%s: pump stev RSP_DISC state(%d)\n",
+ ch->is->name, ch->state);
+ if (ch->state == STFAX_ESCAPE) {
+ p1 = 5;
+ switch (ch->newcmd) {
+ case 0:
+ ch->state = STFAX_READY;
+ break;
+ case PCTRL_CMD_FTM:
+ p1 = 2;
+ case PCTRL_CMD_FTH:
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_SILON, 1, &p1);
+ ch->state = STFAX_SILDET;
+ break;
+ case PCTRL_CMD_FRH:
+ case PCTRL_CMD_FRM:
+ ch->mod = ch->newmod;
+ p1 = ch->newmod;
+ ch->newmod = 0;
+ ch->cmd = ch->newcmd;
+ ch->newcmd = 0;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ ch->cmd, 1, &p1);
+ ch->state = STFAX_LINE;
+ ch->try_mod = 3;
+ break;
+ default:
+ pr_debug("%s: RSP_DISC unknown newcmd %x\n",
+ ch->is->name, ch->newcmd);
+ break;
+ }
+ } else if (ch->state == STFAX_ACTIV) {
+ if (test_and_clear_bit(FLG_LL_OK, &ch->bch.Flags))
+ deliver_status(ch, HW_MOD_OK);
+ else if (ch->cmd == PCTRL_CMD_FRM)
+ deliver_status(ch, HW_MOD_NOCARR);
+ else
+ deliver_status(ch, HW_MOD_FCERROR);
+ ch->state = STFAX_READY;
+ } else if (ch->state != STFAX_SILDET) {
+ /* ignore in STFAX_SILDET */
+ ch->state = STFAX_READY;
+ deliver_status(ch, HW_MOD_FCERROR);
+ }
+ break;
+ case PSEV_RSP_SILDET:
+ pr_debug("%s: pump stev RSP_SILDET\n", ch->is->name);
+ if (ch->state == STFAX_SILDET) {
+ ch->mod = ch->newmod;
+ p1 = ch->newmod;
+ ch->newmod = 0;
+ ch->cmd = ch->newcmd;
+ ch->newcmd = 0;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ ch->cmd, 1, &p1);
+ ch->state = STFAX_LINE;
+ ch->try_mod = 3;
+ }
+ break;
+ case PSEV_RSP_SILOFF:
+ pr_debug("%s: pump stev RSP_SILOFF\n", ch->is->name);
+ break;
+ case PSEV_RSP_FCERR:
+ if (ch->state == STFAX_LINE) {
+ pr_debug("%s: pump stev RSP_FCERR try %d\n",
+ ch->is->name, ch->try_mod);
+ if (ch->try_mod--) {
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL,
+ ch->cmd, 1, &ch->mod);
+ break;
+ }
+ }
+ pr_debug("%s: pump stev RSP_FCERR\n", ch->is->name);
+ ch->state = STFAX_ESCAPE;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC,
+ 0, NULL);
+ deliver_status(ch, HW_MOD_FCERROR);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+mISDNisar_irq(struct isar_hw *isar)
+{
+ struct isar_ch *ch;
+
+ get_irq_infos(isar);
+ switch (isar->iis & ISAR_IIS_MSCMSD) {
+ case ISAR_IIS_RDATA:
+ ch = sel_bch_isar(isar, isar->iis >> 6);
+ if (ch)
+ isar_rcv_frame(ch);
+ else {
+ pr_debug("%s: ISAR spurious IIS_RDATA %x/%x/%x\n",
+ isar->name, isar->iis, isar->cmsb,
+ isar->clsb);
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ }
+ break;
+ case ISAR_IIS_GSTEV:
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ isar->bstat |= isar->cmsb;
+ check_send(isar, isar->cmsb);
+ break;
+ case ISAR_IIS_BSTEV:
+#ifdef ERROR_STATISTIC
+ ch = sel_bch_isar(isar, isar->iis >> 6);
+ if (ch) {
+ if (isar->cmsb == BSTEV_TBO)
+ ch->bch.err_tx++;
+ if (isar->cmsb == BSTEV_RBO)
+ ch->bch.err_rdo++;
+ }
+#endif
+ pr_debug("%s: Buffer STEV dpath%d msb(%x)\n",
+ isar->name, isar->iis>>6, isar->cmsb);
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ break;
+ case ISAR_IIS_PSTEV:
+ ch = sel_bch_isar(isar, isar->iis >> 6);
+ if (ch) {
+ rcv_mbox(isar, NULL);
+ if (ch->bch.state == ISDN_P_B_MODEM_ASYNC)
+ isar_pump_statev_modem(ch, isar->cmsb);
+ else if (ch->bch.state == ISDN_P_B_T30_FAX)
+ isar_pump_statev_fax(ch, isar->cmsb);
+ else if (ch->bch.state == ISDN_P_B_RAW) {
+ int tt;
+ tt = isar->cmsb | 0x30;
+ if (tt == 0x3e)
+ tt = '*';
+ else if (tt == 0x3f)
+ tt = '#';
+ else if (tt > '9')
+ tt += 7;
+ tt |= DTMF_TONE_VAL;
+ _queue_data(&ch->bch.ch, PH_CONTROL_IND,
+ MISDN_ID_ANY, sizeof(tt), &tt,
+ GFP_ATOMIC);
+ } else
+ pr_debug("%s: ISAR IIS_PSTEV pm %d sta %x\n",
+ isar->name, ch->bch.state,
+ isar->cmsb);
+ } else {
+ pr_debug("%s: ISAR spurious IIS_PSTEV %x/%x/%x\n",
+ isar->name, isar->iis, isar->cmsb,
+ isar->clsb);
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ }
+ break;
+ case ISAR_IIS_PSTRSP:
+ ch = sel_bch_isar(isar, isar->iis >> 6);
+ if (ch) {
+ rcv_mbox(isar, NULL);
+ isar_pump_status_rsp(ch);
+ } else {
+ pr_debug("%s: ISAR spurious IIS_PSTRSP %x/%x/%x\n",
+ isar->name, isar->iis, isar->cmsb,
+ isar->clsb);
+ isar->write_reg(isar->hw, ISAR_IIA, 0);
+ }
+ break;
+ case ISAR_IIS_DIAG:
+ case ISAR_IIS_BSTRSP:
+ case ISAR_IIS_IOM2RSP:
+ rcv_mbox(isar, NULL);
+ break;
+ case ISAR_IIS_INVMSG:
+ rcv_mbox(isar, NULL);
+ pr_debug("%s: invalid msg his:%x\n", isar->name, isar->cmsb);
+ break;
+ default:
+ rcv_mbox(isar, NULL);
+ pr_debug("%s: unhandled msg iis(%x) ctrl(%x/%x)\n",
+ isar->name, isar->iis, isar->cmsb, isar->clsb);
+ break;
+ }
+}
+EXPORT_SYMBOL(mISDNisar_irq);
+
+static void
+ftimer_handler(unsigned long data)
+{
+ struct isar_ch *ch = (struct isar_ch *)data;
+
+ pr_debug("%s: ftimer flags %lx\n", ch->is->name, ch->bch.Flags);
+ test_and_clear_bit(FLG_FTI_RUN, &ch->bch.Flags);
+ if (test_and_clear_bit(FLG_LL_CONN, &ch->bch.Flags))
+ deliver_status(ch, HW_MOD_CONNECT);
+}
+
+static void
+setup_pump(struct isar_ch *ch) {
+ u8 dps = SET_DPS(ch->dpath);
+ u8 ctrl, param[6];
+
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_HDLC:
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL);
+ break;
+ case ISDN_P_B_L2DTMF:
+ if (test_bit(FLG_DTMFSEND, &ch->bch.Flags)) {
+ param[0] = 5; /* TOA 5 db */
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG,
+ PMOD_DTMF_TRANS, 1, param);
+ } else {
+ param[0] = 40; /* REL -46 dbm */
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG,
+ PMOD_DTMF, 1, param);
+ }
+ case ISDN_P_B_MODEM_ASYNC:
+ ctrl = PMOD_DATAMODEM;
+ if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) {
+ ctrl |= PCTRL_ORIG;
+ param[5] = PV32P6_CTN;
+ } else {
+ param[5] = PV32P6_ATN;
+ }
+ param[0] = 6; /* 6 db */
+ param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
+ PV32P2_V22C | PV32P2_V21 | PV32P2_BEL;
+ param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
+ param[3] = PV32P4_UT144;
+ param[4] = PV32P5_UT144;
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param);
+ break;
+ case ISDN_P_B_T30_FAX:
+ ctrl = PMOD_FAX;
+ if (test_bit(FLG_ORIGIN, &ch->bch.Flags)) {
+ ctrl |= PCTRL_ORIG;
+ param[1] = PFAXP2_CTN;
+ } else {
+ param[1] = PFAXP2_ATN;
+ }
+ param[0] = 6; /* 6 db */
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
+ ch->state = STFAX_NULL;
+ ch->newcmd = 0;
+ ch->newmod = 0;
+ test_and_set_bit(FLG_FTI_RUN, &ch->bch.Flags);
+ break;
+ }
+ udelay(1000);
+ send_mbox(ch->is, dps | ISAR_HIS_PSTREQ, 0, 0, NULL);
+ udelay(1000);
+}
+
+static void
+setup_sart(struct isar_ch *ch) {
+ u8 dps = SET_DPS(ch->dpath);
+ u8 ctrl, param[2] = {0, 0};
+
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE,
+ 0, NULL);
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_L2DTMF:
+ send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_BINARY,
+ 2, param);
+ break;
+ case ISDN_P_B_HDLC:
+ case ISDN_P_B_T30_FAX:
+ send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, SMODE_HDLC,
+ 1, param);
+ break;
+ case ISDN_P_B_MODEM_ASYNC:
+ ctrl = SMODE_V14 | SCTRL_HDMC_BOTH;
+ param[0] = S_P1_CHS_8;
+ param[1] = S_P2_BFT_DEF;
+ send_mbox(ch->is, dps | ISAR_HIS_SARTCFG, ctrl, 2, param);
+ break;
+ }
+ udelay(1000);
+ send_mbox(ch->is, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
+ udelay(1000);
+}
+
+static void
+setup_iom2(struct isar_ch *ch) {
+ u8 dps = SET_DPS(ch->dpath);
+ u8 cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0};
+
+ if (ch->bch.nr == 2) {
+ msg[1] = 1;
+ msg[3] = 1;
+ }
+ switch (ch->bch.state) {
+ case ISDN_P_NONE:
+ cmsb = 0;
+ /* dummy slot */
+ msg[1] = ch->dpath + 2;
+ msg[3] = ch->dpath + 2;
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_HDLC:
+ break;
+ case ISDN_P_B_MODEM_ASYNC:
+ case ISDN_P_B_T30_FAX:
+ cmsb |= IOM_CTRL_RCV;
+ case ISDN_P_B_L2DTMF:
+ if (test_bit(FLG_DTMFSEND, &ch->bch.Flags))
+ cmsb |= IOM_CTRL_RCV;
+ cmsb |= IOM_CTRL_ALAW;
+ break;
+ }
+ send_mbox(ch->is, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg);
+ udelay(1000);
+ send_mbox(ch->is, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL);
+ udelay(1000);
+}
+
+static int
+modeisar(struct isar_ch *ch, u32 bprotocol)
+{
+ /* Here we are selecting the best datapath for requested protocol */
+ if (ch->bch.state == ISDN_P_NONE) { /* New Setup */
+ switch (bprotocol) {
+ case ISDN_P_NONE: /* init */
+ if (!ch->dpath)
+ /* no init for dpath 0 */
+ return 0;
+ test_and_clear_bit(FLG_HDLC, &ch->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &ch->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ case ISDN_P_B_HDLC:
+ /* best is datapath 2 */
+ if (!test_and_set_bit(ISAR_DP2_USE, &ch->is->Flags))
+ ch->dpath = 2;
+ else if (!test_and_set_bit(ISAR_DP1_USE,
+ &ch->is->Flags))
+ ch->dpath = 1;
+ else {
+ pr_info("modeisar both pathes in use\n");
+ return -EBUSY;
+ }
+ if (bprotocol == ISDN_P_B_HDLC)
+ test_and_set_bit(FLG_HDLC, &ch->bch.Flags);
+ else
+ test_and_set_bit(FLG_TRANSPARENT,
+ &ch->bch.Flags);
+ break;
+ case ISDN_P_B_MODEM_ASYNC:
+ case ISDN_P_B_T30_FAX:
+ case ISDN_P_B_L2DTMF:
+ /* only datapath 1 */
+ if (!test_and_set_bit(ISAR_DP1_USE, &ch->is->Flags))
+ ch->dpath = 1;
+ else {
+ pr_info("%s: ISAR modeisar analog functions"
+ "only with DP1\n", ch->is->name);
+ return -EBUSY;
+ }
+ break;
+ default:
+ pr_info("%s: protocol not known %x\n", ch->is->name,
+ bprotocol);
+ return -ENOPROTOOPT;
+ }
+ }
+ pr_debug("%s: ISAR ch%d dp%d protocol %x->%x\n", ch->is->name,
+ ch->bch.nr, ch->dpath, ch->bch.state, bprotocol);
+ ch->bch.state = bprotocol;
+ setup_pump(ch);
+ setup_iom2(ch);
+ setup_sart(ch);
+ if (ch->bch.state == ISDN_P_NONE) {
+ /* Clear resources */
+ if (ch->dpath == 1)
+ test_and_clear_bit(ISAR_DP1_USE, &ch->is->Flags);
+ else if (ch->dpath == 2)
+ test_and_clear_bit(ISAR_DP2_USE, &ch->is->Flags);
+ ch->dpath = 0;
+ ch->is->ctrl(ch->is->hw, HW_DEACT_IND, ch->bch.nr);
+ } else
+ ch->is->ctrl(ch->is->hw, HW_ACTIVATE_IND, ch->bch.nr);
+ return 0;
+}
+
+static void
+isar_pump_cmd(struct isar_ch *ch, u32 cmd, u8 para)
+{
+ u8 dps = SET_DPS(ch->dpath);
+ u8 ctrl = 0, nom = 0, p1 = 0;
+
+ pr_debug("%s: isar_pump_cmd %x/%x state(%x)\n",
+ ch->is->name, cmd, para, ch->bch.state);
+ switch (cmd) {
+ case HW_MOD_FTM:
+ if (ch->state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTM;
+ nom = 1;
+ ch->state = STFAX_LINE;
+ ch->cmd = ctrl;
+ ch->mod = para;
+ ch->newmod = 0;
+ ch->newcmd = 0;
+ ch->try_mod = 3;
+ } else if ((ch->state == STFAX_ACTIV) &&
+ (ch->cmd == PCTRL_CMD_FTM) && (ch->mod == para))
+ deliver_status(ch, HW_MOD_CONNECT);
+ else {
+ ch->newmod = para;
+ ch->newcmd = PCTRL_CMD_FTM;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ ch->state = STFAX_ESCAPE;
+ }
+ break;
+ case HW_MOD_FTH:
+ if (ch->state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTH;
+ nom = 1;
+ ch->state = STFAX_LINE;
+ ch->cmd = ctrl;
+ ch->mod = para;
+ ch->newmod = 0;
+ ch->newcmd = 0;
+ ch->try_mod = 3;
+ } else if ((ch->state == STFAX_ACTIV) &&
+ (ch->cmd == PCTRL_CMD_FTH) && (ch->mod == para))
+ deliver_status(ch, HW_MOD_CONNECT);
+ else {
+ ch->newmod = para;
+ ch->newcmd = PCTRL_CMD_FTH;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ ch->state = STFAX_ESCAPE;
+ }
+ break;
+ case HW_MOD_FRM:
+ if (ch->state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRM;
+ nom = 1;
+ ch->state = STFAX_LINE;
+ ch->cmd = ctrl;
+ ch->mod = para;
+ ch->newmod = 0;
+ ch->newcmd = 0;
+ ch->try_mod = 3;
+ } else if ((ch->state == STFAX_ACTIV) &&
+ (ch->cmd == PCTRL_CMD_FRM) && (ch->mod == para))
+ deliver_status(ch, HW_MOD_CONNECT);
+ else {
+ ch->newmod = para;
+ ch->newcmd = PCTRL_CMD_FRM;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ ch->state = STFAX_ESCAPE;
+ }
+ break;
+ case HW_MOD_FRH:
+ if (ch->state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRH;
+ nom = 1;
+ ch->state = STFAX_LINE;
+ ch->cmd = ctrl;
+ ch->mod = para;
+ ch->newmod = 0;
+ ch->newcmd = 0;
+ ch->try_mod = 3;
+ } else if ((ch->state == STFAX_ACTIV) &&
+ (ch->cmd == PCTRL_CMD_FRH) && (ch->mod == para))
+ deliver_status(ch, HW_MOD_CONNECT);
+ else {
+ ch->newmod = para;
+ ch->newcmd = PCTRL_CMD_FRH;
+ nom = 0;
+ ctrl = PCTRL_CMD_ESC;
+ ch->state = STFAX_ESCAPE;
+ }
+ break;
+ case PCTRL_CMD_TDTMF:
+ p1 = para;
+ nom = 1;
+ ctrl = PCTRL_CMD_TDTMF;
+ break;
+ }
+ if (ctrl)
+ send_mbox(ch->is, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
+}
+
+static void
+isar_setup(struct isar_hw *isar)
+{
+ u8 msg;
+ int i;
+
+ /* Dpath 1, 2 */
+ msg = 61;
+ for (i = 0; i < 2; i++) {
+ /* Buffer Config */
+ send_mbox(isar, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) |
+ ISAR_HIS_P12CFG, 4, 1, &msg);
+ isar->ch[i].mml = msg;
+ isar->ch[i].bch.state = 0;
+ isar->ch[i].dpath = i + 1;
+ modeisar(&isar->ch[i], ISDN_P_NONE);
+ }
+}
+
+static int
+isar_l2l1(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct isar_ch *ich = container_of(bch, struct isar_ch, bch);
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id, *val;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ ret = 0;
+ isar_fill_fifo(ich);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = modeisar(ich, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ mISDN_clear_bchannel(bch);
+ modeisar(ich, ISDN_P_NONE);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ case PH_CONTROL_REQ:
+ val = (u32 *)skb->data;
+ pr_debug("%s: PH_CONTROL | REQUEST %x/%x\n", ich->is->name,
+ hh->id, *val);
+ if ((hh->id == 0) && ((*val & ~DTMF_TONE_MASK) ==
+ DTMF_TONE_VAL)) {
+ if (bch->state == ISDN_P_B_L2DTMF) {
+ char tt = *val & DTMF_TONE_MASK;
+
+ if (tt == '*')
+ tt = 0x1e;
+ else if (tt == '#')
+ tt = 0x1f;
+ else if (tt > '9')
+ tt -= 7;
+ tt &= 0x1f;
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ isar_pump_cmd(ich, PCTRL_CMD_TDTMF, tt);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ } else {
+ pr_info("%s: DTMF send wrong protocol %x\n",
+ __func__, bch->state);
+ return -EINVAL;
+ }
+ } else if ((hh->id == HW_MOD_FRM) || (hh->id == HW_MOD_FRH) ||
+ (hh->id == HW_MOD_FTM) || (hh->id == HW_MOD_FTH)) {
+ for (id = 0; id < FAXMODCNT; id++)
+ if (faxmodulation[id] == *val)
+ break;
+ if ((FAXMODCNT > id) &&
+ test_bit(FLG_INITIALIZED, &bch->Flags)) {
+ pr_debug("%s: isar: new mod\n", ich->is->name);
+ isar_pump_cmd(ich, hh->id, *val);
+ ret = 0;
+ } else {
+ pr_info("%s: wrong modulation\n",
+ ich->is->name);
+ ret = -EINVAL;
+ }
+ } else if (hh->id == HW_MOD_LASTDATA)
+ test_and_set_bit(FLG_DLEETX, &bch->Flags);
+ else {
+ pr_info("%s: unknown PH_CONTROL_REQ %x\n",
+ ich->is->name, hh->id);
+ ret = -EINVAL;
+ }
+ default:
+ pr_info("%s: %s unknown prim(%x,%x)\n",
+ ich->is->name, __func__, hh->prim, hh->id);
+ ret = -EINVAL;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: unknown Op %x\n", __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+isar_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct isar_ch *ich = container_of(bch, struct isar_ch, bch);
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", ich->is->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(ich->is->hwlock, flags);
+ mISDN_freebchannel(bch);
+ modeisar(ich, ISDN_P_NONE);
+ spin_unlock_irqrestore(ich->is->hwlock, flags);
+ } else {
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(ich->is->owner);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n",
+ ich->is->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static void
+free_isar(struct isar_hw *isar)
+{
+ modeisar(&isar->ch[0], ISDN_P_NONE);
+ modeisar(&isar->ch[1], ISDN_P_NONE);
+ del_timer(&isar->ch[0].ftimer);
+ del_timer(&isar->ch[1].ftimer);
+ test_and_clear_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags);
+ test_and_clear_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags);
+}
+
+static int
+init_isar(struct isar_hw *isar)
+{
+ int cnt = 3;
+
+ while (cnt--) {
+ isar->version = ISARVersion(isar);
+ if (isar->ch[0].bch.debug & DEBUG_HW)
+ pr_notice("%s: Testing version %d (%d time)\n",
+ isar->name, isar->version, 3 - cnt);
+ if (isar->version == 1)
+ break;
+ isar->ctrl(isar->hw, HW_RESET_REQ, 0);
+ }
+ if (isar->version != 1)
+ return -EINVAL;
+ isar->ch[0].ftimer.function = &ftimer_handler;
+ isar->ch[0].ftimer.data = (long)&isar->ch[0];
+ init_timer(&isar->ch[0].ftimer);
+ test_and_set_bit(FLG_INITIALIZED, &isar->ch[0].bch.Flags);
+ isar->ch[1].ftimer.function = &ftimer_handler;
+ isar->ch[1].ftimer.data = (long)&isar->ch[1];
+ init_timer(&isar->ch[1].ftimer);
+ test_and_set_bit(FLG_INITIALIZED, &isar->ch[1].bch.Flags);
+ return 0;
+}
+
+static int
+isar_open(struct isar_hw *isar, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &isar->ch[rq->adr.channel - 1].bch;
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+u32
+mISDNisar_init(struct isar_hw *isar, void *hw)
+{
+ u32 ret, i;
+
+ isar->hw = hw;
+ for (i = 0; i < 2; i++) {
+ isar->ch[i].bch.nr = i + 1;
+ mISDN_initbchannel(&isar->ch[i].bch, MAX_DATA_MEM);
+ isar->ch[i].bch.ch.nr = i + 1;
+ isar->ch[i].bch.ch.send = &isar_l2l1;
+ isar->ch[i].bch.ch.ctrl = isar_bctrl;
+ isar->ch[i].bch.hw = hw;
+ isar->ch[i].is = isar;
+ }
+
+ isar->init = &init_isar;
+ isar->release = &free_isar;
+ isar->firmware = &load_firmware;
+ isar->open = &isar_open;
+
+ ret = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_L2DTMF & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_MODEM_ASYNC & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_T30_FAX & ISDN_P_B_MASK));
+
+ return ret;
+}
+EXPORT_SYMBOL(mISDNisar_init);
+
+static int isar_mod_init(void)
+{
+ pr_notice("mISDN: ISAR driver Rev. %s\n", ISAR_REV);
+ return 0;
+}
+
+static void isar_mod_cleanup(void)
+{
+ pr_notice("mISDN: ISAR module unloaded\n");
+}
+module_init(isar_mod_init);
+module_exit(isar_mod_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
new file mode 100644
index 00000000000..6c1b164937a
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -0,0 +1,1156 @@
+/*
+ * NETJet mISDN driver
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "ipac.h"
+#include "iohelper.h"
+#include "netjet.h"
+#include <linux/isdn/hdlc.h>
+
+#define NETJET_REV "2.0"
+
+enum nj_types {
+ NETJET_S_TJ300,
+ NETJET_S_TJ320,
+ ENTERNOW__TJ320,
+};
+
+struct tiger_dma {
+ size_t size;
+ u32 *start;
+ int idx;
+ u32 dmastart;
+ u32 dmairq;
+ u32 dmaend;
+ u32 dmacur;
+};
+
+struct tiger_hw;
+
+struct tiger_ch {
+ struct bchannel bch;
+ struct tiger_hw *nj;
+ int idx;
+ int free;
+ int lastrx;
+ u16 rxstate;
+ u16 txstate;
+ struct isdnhdlc_vars hsend;
+ struct isdnhdlc_vars hrecv;
+ u8 *hsbuf;
+ u8 *hrbuf;
+};
+
+#define TX_INIT 0x0001
+#define TX_IDLE 0x0002
+#define TX_RUN 0x0004
+#define TX_UNDERRUN 0x0100
+#define RX_OVERRUN 0x0100
+
+#define LOG_SIZE 64
+
+struct tiger_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ char name[MISDN_MAX_IDLEN];
+ enum nj_types typ;
+ int irq;
+ u32 irqcnt;
+ u32 base;
+ size_t base_s;
+ dma_addr_t dma;
+ void *dma_p;
+ spinlock_t lock; /* lock HW */
+ struct isac_hw isac;
+ struct tiger_dma send;
+ struct tiger_dma recv;
+ struct tiger_ch bc[2];
+ u8 ctrlreg;
+ u8 dmactrl;
+ u8 auxd;
+ u8 last_is0;
+ u8 irqmask0;
+ char log[LOG_SIZE];
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+static u32 debug;
+static int nj_cnt;
+
+static void
+_set_debug(struct tiger_hw *card)
+{
+ card->isac.dch.debug = debug;
+ card->bc[0].bch.debug = debug;
+ card->bc[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct tiger_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(NETJET_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Netjet debug mask");
+
+static void
+nj_disable_hwirq(struct tiger_hw *card)
+{
+ outb(0, card->base + NJ_IRQMASK0);
+ outb(0, card->base + NJ_IRQMASK1);
+}
+
+
+static u8
+ReadISAC_nj(void *p, u8 offset)
+{
+ struct tiger_hw *card = p;
+ u8 ret;
+
+ card->auxd &= 0xfc;
+ card->auxd |= (offset >> 4) & 3;
+ outb(card->auxd, card->base + NJ_AUXDATA);
+ ret = inb(card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
+ return ret;
+}
+
+static void
+WriteISAC_nj(void *p, u8 offset, u8 value)
+{
+ struct tiger_hw *card = p;
+
+ card->auxd &= 0xfc;
+ card->auxd |= (offset >> 4) & 3;
+ outb(card->auxd, card->base + NJ_AUXDATA);
+ outb(value, card->base + NJ_ISAC_OFF + ((offset & 0x0f) << 2));
+}
+
+static void
+ReadFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
+{
+ struct tiger_hw *card = p;
+
+ card->auxd &= 0xfc;
+ outb(card->auxd, card->base + NJ_AUXDATA);
+ insb(card->base + NJ_ISAC_OFF, data, size);
+}
+
+static void
+WriteFiFoISAC_nj(void *p, u8 offset, u8 *data, int size)
+{
+ struct tiger_hw *card = p;
+
+ card->auxd &= 0xfc;
+ outb(card->auxd, card->base + NJ_AUXDATA);
+ outsb(card->base + NJ_ISAC_OFF, data, size);
+}
+
+static void
+fill_mem(struct tiger_ch *bc, u32 idx, u32 cnt, u32 fill)
+{
+ struct tiger_hw *card = bc->bch.hw;
+ u32 mask = 0xff, val;
+
+ pr_debug("%s: B%1d fill %02x len %d idx %d/%d\n", card->name,
+ bc->bch.nr, fill, cnt, idx, card->send.idx);
+ if (bc->bch.nr & 2) {
+ fill <<= 8;
+ mask <<= 8;
+ }
+ mask ^= 0xffffffff;
+ while (cnt--) {
+ val = card->send.start[idx];
+ val &= mask;
+ val |= fill;
+ card->send.start[idx++] = val;
+ if (idx >= card->send.size)
+ idx = 0;
+ }
+}
+
+static int
+mode_tiger(struct tiger_ch *bc, u32 protocol)
+{
+ struct tiger_hw *card = bc->bch.hw;
+
+ pr_debug("%s: B%1d protocol %x-->%x\n", card->name,
+ bc->bch.nr, bc->bch.state, protocol);
+ switch (protocol) {
+ case ISDN_P_NONE:
+ if (bc->bch.state == ISDN_P_NONE)
+ break;
+ fill_mem(bc, 0, card->send.size, 0xff);
+ bc->bch.state = protocol;
+ /* only stop dma and interrupts if both channels NULL */
+ if ((card->bc[0].bch.state == ISDN_P_NONE) &&
+ (card->bc[1].bch.state == ISDN_P_NONE)) {
+ card->dmactrl = 0;
+ outb(card->dmactrl, card->base + NJ_DMACTRL);
+ outb(0, card->base + NJ_IRQMASK0);
+ }
+ test_and_clear_bit(FLG_HDLC, &bc->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &bc->bch.Flags);
+ bc->txstate = 0;
+ bc->rxstate = 0;
+ bc->lastrx = -1;
+ break;
+ case ISDN_P_B_RAW:
+ test_and_set_bit(FLG_TRANSPARENT, &bc->bch.Flags);
+ bc->bch.state = protocol;
+ bc->idx = 0;
+ bc->free = card->send.size/2;
+ bc->rxstate = 0;
+ bc->txstate = TX_INIT | TX_IDLE;
+ bc->lastrx = -1;
+ if (!card->dmactrl) {
+ card->dmactrl = 1;
+ outb(card->dmactrl, card->base + NJ_DMACTRL);
+ outb(0x0f, card->base + NJ_IRQMASK0);
+ }
+ break;
+ case ISDN_P_B_HDLC:
+ test_and_set_bit(FLG_HDLC, &bc->bch.Flags);
+ bc->bch.state = protocol;
+ bc->idx = 0;
+ bc->free = card->send.size/2;
+ bc->rxstate = 0;
+ bc->txstate = TX_INIT | TX_IDLE;
+ isdnhdlc_rcv_init(&bc->hrecv, 0);
+ isdnhdlc_out_init(&bc->hsend, 0);
+ bc->lastrx = -1;
+ if (!card->dmactrl) {
+ card->dmactrl = 1;
+ outb(card->dmactrl, card->base + NJ_DMACTRL);
+ outb(0x0f, card->base + NJ_IRQMASK0);
+ }
+ break;
+ default:
+ pr_info("%s: %s protocol %x not handled\n", card->name,
+ __func__, protocol);
+ return -ENOPROTOOPT;
+ }
+ card->send.dmacur = inl(card->base + NJ_DMA_READ_ADR);
+ card->recv.dmacur = inl(card->base + NJ_DMA_WRITE_ADR);
+ card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+ card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
+ pr_debug("%s: %s ctrl %x irq %02x/%02x idx %d/%d\n",
+ card->name, __func__,
+ inb(card->base + NJ_DMACTRL),
+ inb(card->base + NJ_IRQMASK0),
+ inb(card->base + NJ_IRQSTAT0),
+ card->send.idx,
+ card->recv.idx);
+ return 0;
+}
+
+static void
+nj_reset(struct tiger_hw *card)
+{
+ outb(0xff, card->base + NJ_CTRL); /* Reset On */
+ mdelay(1);
+
+ /* now edge triggered for TJ320 GE 13/07/00 */
+ /* see comment in IRQ function */
+ if (card->typ == NETJET_S_TJ320) /* TJ320 */
+ card->ctrlreg = 0x40; /* Reset Off and status read clear */
+ else
+ card->ctrlreg = 0x00; /* Reset Off and status read clear */
+ outb(card->ctrlreg, card->base + NJ_CTRL);
+ mdelay(10);
+
+ /* configure AUX pins (all output except ISAC IRQ pin) */
+ card->auxd = 0;
+ card->dmactrl = 0;
+ outb(~NJ_ISACIRQ, card->base + NJ_AUXCTRL);
+ outb(NJ_ISACIRQ, card->base + NJ_IRQMASK1);
+ outb(card->auxd, card->base + NJ_AUXDATA);
+}
+
+static int
+inittiger(struct tiger_hw *card)
+{
+ int i;
+
+ card->dma_p = pci_alloc_consistent(card->pdev, NJ_DMA_SIZE,
+ &card->dma);
+ if (!card->dma_p) {
+ pr_info("%s: No DMA memory\n", card->name);
+ return -ENOMEM;
+ }
+ if ((u64)card->dma > 0xffffffff) {
+ pr_info("%s: DMA outside 32 bit\n", card->name);
+ return -ENOMEM;
+ }
+ for (i = 0; i < 2; i++) {
+ card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_KERNEL);
+ if (!card->bc[i].hsbuf) {
+ pr_info("%s: no B%d send buffer\n", card->name, i + 1);
+ return -ENOMEM;
+ }
+ card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_KERNEL);
+ if (!card->bc[i].hrbuf) {
+ pr_info("%s: no B%d recv buffer\n", card->name, i + 1);
+ return -ENOMEM;
+ }
+ }
+ memset(card->dma_p, 0xff, NJ_DMA_SIZE);
+
+ card->send.start = card->dma_p;
+ card->send.dmastart = (u32)card->dma;
+ card->send.dmaend = card->send.dmastart +
+ (4 * (NJ_DMA_TXSIZE - 1));
+ card->send.dmairq = card->send.dmastart +
+ (4 * ((NJ_DMA_TXSIZE / 2) - 1));
+ card->send.size = NJ_DMA_TXSIZE;
+
+ if (debug & DEBUG_HW)
+ pr_notice("%s: send buffer phy %#x - %#x - %#x virt %p"
+ " size %zu u32\n", card->name,
+ card->send.dmastart, card->send.dmairq,
+ card->send.dmaend, card->send.start, card->send.size);
+
+ outl(card->send.dmastart, card->base + NJ_DMA_READ_START);
+ outl(card->send.dmairq, card->base + NJ_DMA_READ_IRQ);
+ outl(card->send.dmaend, card->base + NJ_DMA_READ_END);
+
+ card->recv.start = card->dma_p + (NJ_DMA_SIZE / 2);
+ card->recv.dmastart = (u32)card->dma + (NJ_DMA_SIZE / 2);
+ card->recv.dmaend = card->recv.dmastart +
+ (4 * (NJ_DMA_RXSIZE - 1));
+ card->recv.dmairq = card->recv.dmastart +
+ (4 * ((NJ_DMA_RXSIZE / 2) - 1));
+ card->recv.size = NJ_DMA_RXSIZE;
+
+ if (debug & DEBUG_HW)
+ pr_notice("%s: recv buffer phy %#x - %#x - %#x virt %p"
+ " size %zu u32\n", card->name,
+ card->recv.dmastart, card->recv.dmairq,
+ card->recv.dmaend, card->recv.start, card->recv.size);
+
+ outl(card->recv.dmastart, card->base + NJ_DMA_WRITE_START);
+ outl(card->recv.dmairq, card->base + NJ_DMA_WRITE_IRQ);
+ outl(card->recv.dmaend, card->base + NJ_DMA_WRITE_END);
+ return 0;
+}
+
+static void
+read_dma(struct tiger_ch *bc, u32 idx, int cnt)
+{
+ struct tiger_hw *card = bc->bch.hw;
+ int i, stat;
+ u32 val;
+ u8 *p, *pn;
+
+ if (bc->lastrx == idx) {
+ bc->rxstate |= RX_OVERRUN;
+ pr_info("%s: B%1d overrun at idx %d\n", card->name,
+ bc->bch.nr, idx);
+ }
+ bc->lastrx = idx;
+ if (!bc->bch.rx_skb) {
+ bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen, GFP_ATOMIC);
+ if (!bc->bch.rx_skb) {
+ pr_info("%s: B%1d receive out of memory\n",
+ card->name, bc->bch.nr);
+ return;
+ }
+ }
+
+ if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags)) {
+ if ((bc->bch.rx_skb->len + cnt) > bc->bch.maxlen) {
+ pr_debug("%s: B%1d overrun %d\n", card->name,
+ bc->bch.nr, bc->bch.rx_skb->len + cnt);
+ skb_trim(bc->bch.rx_skb, 0);
+ return;
+ }
+ p = skb_put(bc->bch.rx_skb, cnt);
+ } else
+ p = bc->hrbuf;
+
+ for (i = 0; i < cnt; i++) {
+ val = card->recv.start[idx++];
+ if (bc->bch.nr & 2)
+ val >>= 8;
+ if (idx >= card->recv.size)
+ idx = 0;
+ p[i] = val & 0xff;
+ }
+ pn = bc->hrbuf;
+next_frame:
+ if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+ stat = isdnhdlc_decode(&bc->hrecv, pn, cnt, &i,
+ bc->bch.rx_skb->data, bc->bch.maxlen);
+ if (stat > 0) /* valid frame received */
+ p = skb_put(bc->bch.rx_skb, stat);
+ else if (stat == -HDLC_CRC_ERROR)
+ pr_info("%s: B%1d receive frame CRC error\n",
+ card->name, bc->bch.nr);
+ else if (stat == -HDLC_FRAMING_ERROR)
+ pr_info("%s: B%1d receive framing error\n",
+ card->name, bc->bch.nr);
+ else if (stat == -HDLC_LENGTH_ERROR)
+ pr_info("%s: B%1d receive frame too long (> %d)\n",
+ card->name, bc->bch.nr, bc->bch.maxlen);
+ } else
+ stat = cnt;
+
+ if (stat > 0) {
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(card->log, LOG_SIZE, "B%1d-recv %s %d ",
+ bc->bch.nr, card->name, stat);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET,
+ p, stat);
+ }
+ recv_Bchannel(&bc->bch, 0);
+ }
+ if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+ pn += i;
+ cnt -= i;
+ if (!bc->bch.rx_skb) {
+ bc->bch.rx_skb = mI_alloc_skb(bc->bch.maxlen,
+ GFP_ATOMIC);
+ if (!bc->bch.rx_skb) {
+ pr_info("%s: B%1d receive out of memory\n",
+ card->name, bc->bch.nr);
+ return;
+ }
+ }
+ if (cnt > 0)
+ goto next_frame;
+ }
+}
+
+static void
+recv_tiger(struct tiger_hw *card, u8 irq_stat)
+{
+ u32 idx;
+ int cnt = card->recv.size / 2;
+
+ /* Note receive is via the WRITE DMA channel */
+ card->last_is0 &= ~NJ_IRQM0_WR_MASK;
+ card->last_is0 |= (irq_stat & NJ_IRQM0_WR_MASK);
+
+ if (irq_stat & NJ_IRQM0_WR_END)
+ idx = cnt - 1;
+ else
+ idx = card->recv.size - 1;
+
+ if (test_bit(FLG_ACTIVE, &card->bc[0].bch.Flags))
+ read_dma(&card->bc[0], idx, cnt);
+ if (test_bit(FLG_ACTIVE, &card->bc[1].bch.Flags))
+ read_dma(&card->bc[1], idx, cnt);
+}
+
+/* sync with current DMA address at start or after exception */
+static void
+resync(struct tiger_ch *bc, struct tiger_hw *card)
+{
+ card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
+ card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+ if (bc->free > card->send.size / 2)
+ bc->free = card->send.size / 2;
+ /* currently we simple sync to the next complete free area
+ * this hast the advantage that we have always maximum time to
+ * handle TX irq
+ */
+ if (card->send.idx < ((card->send.size / 2) - 1))
+ bc->idx = (card->recv.size / 2) - 1;
+ else
+ bc->idx = card->recv.size - 1;
+ bc->txstate = TX_RUN;
+ pr_debug("%s: %s B%1d free %d idx %d/%d\n", card->name,
+ __func__, bc->bch.nr, bc->free, bc->idx, card->send.idx);
+}
+
+static int bc_next_frame(struct tiger_ch *);
+
+static void
+fill_hdlc_flag(struct tiger_ch *bc)
+{
+ struct tiger_hw *card = bc->bch.hw;
+ int count, i;
+ u32 m, v;
+ u8 *p;
+
+ if (bc->free == 0)
+ return;
+ pr_debug("%s: %s B%1d %d state %x idx %d/%d\n", card->name,
+ __func__, bc->bch.nr, bc->free, bc->txstate,
+ bc->idx, card->send.idx);
+ if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
+ resync(bc, card);
+ count = isdnhdlc_encode(&bc->hsend, NULL, 0, &i,
+ bc->hsbuf, bc->free);
+ pr_debug("%s: B%1d hdlc encoded %d flags\n", card->name,
+ bc->bch.nr, count);
+ bc->free -= count;
+ p = bc->hsbuf;
+ m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
+ for (i = 0; i < count; i++) {
+ if (bc->idx >= card->send.size)
+ bc->idx = 0;
+ v = card->send.start[bc->idx];
+ v &= m;
+ v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
+ card->send.start[bc->idx++] = v;
+ }
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
+ bc->bch.nr, card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+}
+
+static void
+fill_dma(struct tiger_ch *bc)
+{
+ struct tiger_hw *card = bc->bch.hw;
+ int count, i;
+ u32 m, v;
+ u8 *p;
+
+ if (bc->free == 0)
+ return;
+ count = bc->bch.tx_skb->len - bc->bch.tx_idx;
+ if (count <= 0)
+ return;
+ pr_debug("%s: %s B%1d %d/%d/%d/%d state %x idx %d/%d\n", card->name,
+ __func__, bc->bch.nr, count, bc->free, bc->bch.tx_idx,
+ bc->bch.tx_skb->len, bc->txstate, bc->idx, card->send.idx);
+ if (bc->txstate & (TX_IDLE | TX_INIT | TX_UNDERRUN))
+ resync(bc, card);
+ p = bc->bch.tx_skb->data + bc->bch.tx_idx;
+ if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+ count = isdnhdlc_encode(&bc->hsend, p, count, &i,
+ bc->hsbuf, bc->free);
+ pr_debug("%s: B%1d hdlc encoded %d in %d\n", card->name,
+ bc->bch.nr, i, count);
+ bc->bch.tx_idx += i;
+ bc->free -= count;
+ p = bc->hsbuf;
+ } else {
+ if (count > bc->free)
+ count = bc->free;
+ bc->bch.tx_idx += count;
+ bc->free -= count;
+ }
+ m = (bc->bch.nr & 1) ? 0xffffff00 : 0xffff00ff;
+ for (i = 0; i < count; i++) {
+ if (bc->idx >= card->send.size)
+ bc->idx = 0;
+ v = card->send.start[bc->idx];
+ v &= m;
+ v |= (bc->bch.nr & 1) ? (u32)(p[i]) : ((u32)(p[i])) << 8;
+ card->send.start[bc->idx++] = v;
+ }
+ if (debug & DEBUG_HW_BFIFO) {
+ snprintf(card->log, LOG_SIZE, "B%1d-send %s %d ",
+ bc->bch.nr, card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, p, count);
+ }
+ if (bc->free)
+ bc_next_frame(bc);
+}
+
+
+static int
+bc_next_frame(struct tiger_ch *bc)
+{
+ if (bc->bch.tx_skb && bc->bch.tx_idx < bc->bch.tx_skb->len)
+ fill_dma(bc);
+ else {
+ if (bc->bch.tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &bc->bch.Flags))
+ confirm_Bsend(&bc->bch);
+ dev_kfree_skb(bc->bch.tx_skb);
+ }
+ if (get_next_bframe(&bc->bch))
+ fill_dma(bc);
+ else
+ return 0;
+ }
+ return 1;
+}
+
+static void
+send_tiger_bc(struct tiger_hw *card, struct tiger_ch *bc)
+{
+ int ret;
+
+ bc->free += card->send.size / 2;
+ if (bc->free >= card->send.size) {
+ if (!(bc->txstate & (TX_UNDERRUN | TX_INIT))) {
+ pr_info("%s: B%1d TX underrun state %x\n", card->name,
+ bc->bch.nr, bc->txstate);
+ bc->txstate |= TX_UNDERRUN;
+ }
+ bc->free = card->send.size;
+ }
+ ret = bc_next_frame(bc);
+ if (!ret) {
+ if (test_bit(FLG_HDLC, &bc->bch.Flags)) {
+ fill_hdlc_flag(bc);
+ return;
+ }
+ pr_debug("%s: B%1d TX no data free %d idx %d/%d\n", card->name,
+ bc->bch.nr, bc->free, bc->idx, card->send.idx);
+ if (!(bc->txstate & (TX_IDLE | TX_INIT))) {
+ fill_mem(bc, bc->idx, bc->free, 0xff);
+ if (bc->free == card->send.size)
+ bc->txstate |= TX_IDLE;
+ }
+ }
+}
+
+static void
+send_tiger(struct tiger_hw *card, u8 irq_stat)
+{
+ int i;
+
+ /* Note send is via the READ DMA channel */
+ if ((irq_stat & card->last_is0) & NJ_IRQM0_RD_MASK) {
+ pr_info("%s: tiger warn write double dma %x/%x\n",
+ card->name, irq_stat, card->last_is0);
+ return;
+ } else {
+ card->last_is0 &= ~NJ_IRQM0_RD_MASK;
+ card->last_is0 |= (irq_stat & NJ_IRQM0_RD_MASK);
+ }
+ for (i = 0; i < 2; i++) {
+ if (test_bit(FLG_ACTIVE, &card->bc[i].bch.Flags))
+ send_tiger_bc(card, &card->bc[i]);
+ }
+}
+
+static irqreturn_t
+nj_irq(int intno, void *dev_id)
+{
+ struct tiger_hw *card = dev_id;
+ u8 val, s1val, s0val;
+
+ spin_lock(&card->lock);
+ s0val = inb(card->base | NJ_IRQSTAT0);
+ s1val = inb(card->base | NJ_IRQSTAT1);
+ if ((s1val & NJ_ISACIRQ) && (s0val == 0)) {
+ /* shared IRQ */
+ spin_unlock(&card->lock);
+ return IRQ_NONE;
+ }
+ pr_debug("%s: IRQSTAT0 %02x IRQSTAT1 %02x\n", card->name, s0val, s1val);
+ card->irqcnt++;
+ if (!(s1val & NJ_ISACIRQ)) {
+ val = ReadISAC_nj(card, ISAC_ISTA);
+ if (val)
+ mISDNisac_irq(&card->isac, val);
+ }
+
+ if (s0val)
+ /* write to clear */
+ outb(s0val, card->base | NJ_IRQSTAT0);
+ else
+ goto end;
+ s1val = s0val;
+ /* set bits in sval to indicate which page is free */
+ card->recv.dmacur = inl(card->base | NJ_DMA_WRITE_ADR);
+ card->recv.idx = (card->recv.dmacur - card->recv.dmastart) >> 2;
+ if (card->recv.dmacur < card->recv.dmairq)
+ s0val = 0x08; /* the 2nd write area is free */
+ else
+ s0val = 0x04; /* the 1st write area is free */
+
+ card->send.dmacur = inl(card->base | NJ_DMA_READ_ADR);
+ card->send.idx = (card->send.dmacur - card->send.dmastart) >> 2;
+ if (card->send.dmacur < card->send.dmairq)
+ s0val |= 0x02; /* the 2nd read area is free */
+ else
+ s0val |= 0x01; /* the 1st read area is free */
+
+ pr_debug("%s: DMA Status %02x/%02x/%02x %d/%d\n", card->name,
+ s1val, s0val, card->last_is0,
+ card->recv.idx, card->send.idx);
+ /* test if we have a DMA interrupt */
+ if (s0val != card->last_is0) {
+ if ((s0val & NJ_IRQM0_RD_MASK) !=
+ (card->last_is0 & NJ_IRQM0_RD_MASK))
+ /* got a write dma int */
+ send_tiger(card, s0val);
+ if ((s0val & NJ_IRQM0_WR_MASK) !=
+ (card->last_is0 & NJ_IRQM0_WR_MASK))
+ /* got a read dma int */
+ recv_tiger(card, s0val);
+ }
+end:
+ spin_unlock(&card->lock);
+ return IRQ_HANDLED;
+}
+
+static int
+nj_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ int ret = -EINVAL;
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
+ struct tiger_hw *card = bch->hw;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ fill_dma(bc);
+ ret = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(&card->lock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = mode_tiger(bc, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_clear_bchannel(bch);
+ mode_tiger(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+channel_bctrl(struct tiger_ch *bc, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+ struct tiger_hw *card = bc->bch.hw;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+nj_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct tiger_ch *bc = container_of(bch, struct tiger_ch, bch);
+ struct tiger_hw *card = bch->hw;
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_freebchannel(bch);
+ test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
+ test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
+ mode_tiger(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(THIS_MODULE);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bc, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n", card->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static int
+channel_ctrl(struct tiger_hw *card, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP;
+ break;
+ case MISDN_CTRL_LOOP:
+ /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+ if (cq->channel < 0 || cq->channel > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = card->isac.ctrl(&card->isac, HW_TESTLOOP, cq->channel);
+ break;
+ default:
+ pr_info("%s: %s unknown Op %x\n", card->name, __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+open_bchannel(struct tiger_hw *card, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &card->bc[rq->adr.channel - 1].bch;
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+/*
+ * device control function
+ */
+static int
+nj_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct tiger_hw *card = dch->hw;
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = card->isac.open(&card->isac, rq);
+ else
+ err = open_bchannel(card, rq);
+ if (err)
+ break;
+ if (!try_module_get(THIS_MODULE))
+ pr_info("%s: cannot get module\n", card->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", card->name, dch->dev.id,
+ __builtin_return_address(0));
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(card, arg);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x\n",
+ card->name, __func__, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+static int
+nj_init_card(struct tiger_hw *card)
+{
+ u_long flags;
+ int ret;
+
+ spin_lock_irqsave(&card->lock, flags);
+ nj_disable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ card->irq = card->pdev->irq;
+ if (request_irq(card->irq, nj_irq, IRQF_SHARED, card->name, card)) {
+ pr_info("%s: couldn't get interrupt %d\n",
+ card->name, card->irq);
+ card->irq = -1;
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&card->lock, flags);
+ nj_reset(card);
+ ret = card->isac.init(&card->isac);
+ if (ret)
+ goto error;
+ ret = inittiger(card);
+ if (ret)
+ goto error;
+ mode_tiger(&card->bc[0], ISDN_P_NONE);
+ mode_tiger(&card->bc[1], ISDN_P_NONE);
+error:
+ spin_unlock_irqrestore(&card->lock, flags);
+ return ret;
+}
+
+
+static void
+nj_release(struct tiger_hw *card)
+{
+ u_long flags;
+ int i;
+
+ if (card->base_s) {
+ spin_lock_irqsave(&card->lock, flags);
+ nj_disable_hwirq(card);
+ mode_tiger(&card->bc[0], ISDN_P_NONE);
+ mode_tiger(&card->bc[1], ISDN_P_NONE);
+ card->isac.release(&card->isac);
+ spin_unlock_irqrestore(&card->lock, flags);
+ release_region(card->base, card->base_s);
+ card->base_s = 0;
+ }
+ if (card->irq > 0)
+ free_irq(card->irq, card);
+ if (card->isac.dch.dev.dev.class)
+ mISDN_unregister_device(&card->isac.dch.dev);
+
+ for (i = 0; i < 2; i++) {
+ mISDN_freebchannel(&card->bc[i].bch);
+ kfree(card->bc[i].hsbuf);
+ kfree(card->bc[i].hrbuf);
+ }
+ if (card->dma_p)
+ pci_free_consistent(card->pdev, NJ_DMA_SIZE,
+ card->dma_p, card->dma);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ pci_clear_master(card->pdev);
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ kfree(card);
+}
+
+
+static int
+nj_setup(struct tiger_hw *card)
+{
+ card->base = pci_resource_start(card->pdev, 0);
+ card->base_s = pci_resource_len(card->pdev, 0);
+ if (!request_region(card->base, card->base_s, card->name)) {
+ pr_info("%s: NETjet config port %#x-%#x already in use\n",
+ card->name, card->base,
+ (u32)(card->base + card->base_s - 1));
+ card->base_s = 0;
+ return -EIO;
+ }
+ ASSIGN_FUNC(nj, ISAC, card->isac);
+ return 0;
+}
+
+
+static int __devinit
+setup_instance(struct tiger_hw *card)
+{
+ int i, err;
+ u_long flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "netjet.%d", nj_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+
+ _set_debug(card);
+ card->isac.name = card->name;
+ spin_lock_init(&card->lock);
+ card->isac.hwlock = &card->lock;
+ mISDNisac_init(&card->isac, card);
+
+ card->isac.dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ card->isac.dch.dev.D.ctrl = nj_dctrl;
+ for (i = 0; i < 2; i++) {
+ card->bc[i].bch.nr = i + 1;
+ set_channelmap(i + 1, card->isac.dch.dev.channelmap);
+ mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+ card->bc[i].bch.hw = card;
+ card->bc[i].bch.ch.send = nj_l2l1B;
+ card->bc[i].bch.ch.ctrl = nj_bctrl;
+ card->bc[i].bch.ch.nr = i + 1;
+ list_add(&card->bc[i].bch.ch.list,
+ &card->isac.dch.dev.bchannels);
+ card->bc[i].bch.hw = card;
+ }
+ err = nj_setup(card);
+ if (err)
+ goto error;
+ err = mISDN_register_device(&card->isac.dch.dev, &card->pdev->dev,
+ card->name);
+ if (err)
+ goto error;
+ err = nj_init_card(card);
+ if (!err) {
+ nj_cnt++;
+ pr_notice("Netjet %d cards installed\n", nj_cnt);
+ return 0;
+ }
+error:
+ nj_release(card);
+ return err;
+}
+
+static int __devinit
+nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ int cfg;
+ struct tiger_hw *card;
+
+ if (pdev->subsystem_vendor == 0x8086 &&
+ pdev->subsystem_device == 0x0003) {
+ pr_notice("Netjet: Digium X100P/X101P not handled\n");
+ return -ENODEV;
+ }
+
+ if (pdev->subsystem_vendor == 0x55 &&
+ pdev->subsystem_device == 0x02) {
+ pr_notice("Netjet: Enter!Now not handled yet\n");
+ return -ENODEV;
+ }
+
+ card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC);
+ if (!card) {
+ pr_info("No kmem for Netjet\n");
+ return err;
+ }
+
+ card->pdev = pdev;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+
+ printk(KERN_INFO "nj_probe(mISDN): found adapter at %s\n",
+ pci_name(pdev));
+
+ pci_set_master(pdev);
+
+ /* the TJ300 and TJ320 must be detected, the IRQ handling is different
+ * unfortunately the chips use the same device ID, but the TJ320 has
+ * the bit20 in status PCI cfg register set
+ */
+ pci_read_config_dword(pdev, 0x04, &cfg);
+ if (cfg & 0x00100000)
+ card->typ = NETJET_S_TJ320;
+ else
+ card->typ = NETJET_S_TJ300;
+
+ card->base = pci_resource_start(pdev, 0);
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err)
+ pci_set_drvdata(pdev, NULL);
+
+ return err;
+}
+
+
+static void __devexit nj_remove(struct pci_dev *pdev)
+{
+ struct tiger_hw *card = pci_get_drvdata(pdev);
+
+ if (card)
+ nj_release(card);
+ else
+ pr_info("%s drvdata already removed\n", __func__);
+}
+
+/* We cannot select cards with PCI_SUB... IDs, since here are cards with
+ * SUB IDs set to PCI_ANY_ID, so we need to match all and reject
+ * known other cards which not work with this driver - see probe function */
+static struct pci_device_id nj_pci_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_300,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, nj_pci_ids);
+
+static struct pci_driver nj_driver = {
+ .name = "netjet",
+ .probe = nj_probe,
+ .remove = __devexit_p(nj_remove),
+ .id_table = nj_pci_ids,
+};
+
+static int __init nj_init(void)
+{
+ int err;
+
+ pr_notice("Netjet PCI driver Rev. %s\n", NETJET_REV);
+ err = pci_register_driver(&nj_driver);
+ return err;
+}
+
+static void __exit nj_cleanup(void)
+{
+ pci_unregister_driver(&nj_driver);
+}
+
+module_init(nj_init);
+module_exit(nj_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/netjet.h b/drivers/isdn/hardware/mISDN/netjet.h
new file mode 100644
index 00000000000..d061ff99560
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/netjet.h
@@ -0,0 +1,58 @@
+/*
+ * NETjet common header file
+ *
+ * Author Karsten Keil
+ * based on work of Matt Henderson and Daniel Potts,
+ * Traverse Technologies P/L www.traverse.com.au
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define NJ_CTRL 0x00
+#define NJ_DMACTRL 0x01
+#define NJ_AUXCTRL 0x02
+#define NJ_AUXDATA 0x03
+#define NJ_IRQMASK0 0x04
+#define NJ_IRQMASK1 0x05
+#define NJ_IRQSTAT0 0x06
+#define NJ_IRQSTAT1 0x07
+#define NJ_DMA_READ_START 0x08
+#define NJ_DMA_READ_IRQ 0x0c
+#define NJ_DMA_READ_END 0x10
+#define NJ_DMA_READ_ADR 0x14
+#define NJ_DMA_WRITE_START 0x18
+#define NJ_DMA_WRITE_IRQ 0x1c
+#define NJ_DMA_WRITE_END 0x20
+#define NJ_DMA_WRITE_ADR 0x24
+#define NJ_PULSE_CNT 0x28
+
+#define NJ_ISAC_OFF 0xc0
+#define NJ_ISACIRQ 0x10
+
+#define NJ_IRQM0_RD_MASK 0x03
+#define NJ_IRQM0_RD_IRQ 0x01
+#define NJ_IRQM0_RD_END 0x02
+#define NJ_IRQM0_WR_MASK 0x0c
+#define NJ_IRQM0_WR_IRQ 0x04
+#define NJ_IRQM0_WR_END 0x08
+
+/* one page here is no need to be smaller */
+#define NJ_DMA_SIZE 4096
+/* 2 * 64 byte is a compromise between IRQ count and latency */
+#define NJ_DMA_RXSIZE 128 /* 2 * 64 */
+#define NJ_DMA_TXSIZE 128 /* 2 * 64 */
+
diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c
new file mode 100644
index 00000000000..ff3a4e290da
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/speedfax.c
@@ -0,0 +1,526 @@
+/*
+ * speedfax.c low level stuff for Sedlbauer Speedfax+ cards
+ * based on the ISAR DSP
+ * Thanks to Sedlbauer AG for informations and HW
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include <linux/firmware.h>
+#include "ipac.h"
+#include "isar.h"
+
+#define SPEEDFAX_REV "2.0"
+
+#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
+#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
+#define PCI_SUB_ID_SEDLBAUER 0x01
+
+#define SFAX_PCI_ADDR 0xc8
+#define SFAX_PCI_ISAC 0xd0
+#define SFAX_PCI_ISAR 0xe0
+
+/* TIGER 100 Registers */
+
+#define TIGER_RESET_ADDR 0x00
+#define TIGER_EXTERN_RESET_ON 0x01
+#define TIGER_EXTERN_RESET_OFF 0x00
+#define TIGER_AUX_CTRL 0x02
+#define TIGER_AUX_DATA 0x03
+#define TIGER_AUX_IRQMASK 0x05
+#define TIGER_AUX_STATUS 0x07
+
+/* Tiger AUX BITs */
+#define SFAX_AUX_IOMASK 0xdd /* 1 and 5 are inputs */
+#define SFAX_ISAR_RESET_BIT_OFF 0x00
+#define SFAX_ISAR_RESET_BIT_ON 0x01
+#define SFAX_TIGER_IRQ_BIT 0x02
+#define SFAX_LED1_BIT 0x08
+#define SFAX_LED2_BIT 0x10
+
+#define SFAX_PCI_RESET_ON (SFAX_ISAR_RESET_BIT_ON)
+#define SFAX_PCI_RESET_OFF (SFAX_LED1_BIT | SFAX_LED2_BIT)
+
+static int sfax_cnt;
+static u32 debug;
+static u32 irqloops = 4;
+
+struct sfax_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ char name[MISDN_MAX_IDLEN];
+ u32 irq;
+ u32 irqcnt;
+ u32 cfg;
+ struct _ioport p_isac;
+ struct _ioport p_isar;
+ u8 aux_data;
+ spinlock_t lock; /* HW access lock */
+ struct isac_hw isac;
+ struct isar_hw isar;
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static void
+_set_debug(struct sfax_hw *card)
+{
+ card->isac.dch.debug = debug;
+ card->isar.ch[0].bch.debug = debug;
+ card->isar.ch[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct sfax_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(SPEEDFAX_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Speedfax debug mask");
+module_param(irqloops, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(irqloops, "Speedfax maximal irqloops (default 4)");
+
+IOFUNC_IND(ISAC, sfax_hw, p_isac)
+IOFUNC_IND(ISAR, sfax_hw, p_isar)
+
+static irqreturn_t
+speedfax_irq(int intno, void *dev_id)
+{
+ struct sfax_hw *sf = dev_id;
+ u8 val;
+ int cnt = irqloops;
+
+ spin_lock(&sf->lock);
+ val = inb(sf->cfg + TIGER_AUX_STATUS);
+ if (val & SFAX_TIGER_IRQ_BIT) { /* for us or shared ? */
+ spin_unlock(&sf->lock);
+ return IRQ_NONE; /* shared */
+ }
+ sf->irqcnt++;
+ val = ReadISAR_IND(sf, ISAR_IRQBIT);
+Start_ISAR:
+ if (val & ISAR_IRQSTA)
+ mISDNisar_irq(&sf->isar);
+ val = ReadISAC_IND(sf, ISAC_ISTA);
+ if (val)
+ mISDNisac_irq(&sf->isac, val);
+ val = ReadISAR_IND(sf, ISAR_IRQBIT);
+ if ((val & ISAR_IRQSTA) && cnt--)
+ goto Start_ISAR;
+ if (cnt < irqloops)
+ pr_debug("%s: %d irqloops cpu%d\n", sf->name,
+ irqloops - cnt, smp_processor_id());
+ if (irqloops && !cnt)
+ pr_notice("%s: %d IRQ LOOP cpu%d\n", sf->name,
+ irqloops, smp_processor_id());
+ spin_unlock(&sf->lock);
+ return IRQ_HANDLED;
+}
+
+static void
+enable_hwirq(struct sfax_hw *sf)
+{
+ WriteISAC_IND(sf, ISAC_MASK, 0);
+ WriteISAR_IND(sf, ISAR_IRQBIT, ISAR_IRQMSK);
+ outb(SFAX_TIGER_IRQ_BIT, sf->cfg + TIGER_AUX_IRQMASK);
+}
+
+static void
+disable_hwirq(struct sfax_hw *sf)
+{
+ WriteISAC_IND(sf, ISAC_MASK, 0xFF);
+ WriteISAR_IND(sf, ISAR_IRQBIT, 0);
+ outb(0, sf->cfg + TIGER_AUX_IRQMASK);
+}
+
+static void
+reset_speedfax(struct sfax_hw *sf)
+{
+
+ pr_debug("%s: resetting card\n", sf->name);
+ outb(TIGER_EXTERN_RESET_ON, sf->cfg + TIGER_RESET_ADDR);
+ outb(SFAX_PCI_RESET_ON, sf->cfg + TIGER_AUX_DATA);
+ mdelay(1);
+ outb(TIGER_EXTERN_RESET_OFF, sf->cfg + TIGER_RESET_ADDR);
+ sf->aux_data = SFAX_PCI_RESET_OFF;
+ outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
+ mdelay(1);
+}
+
+static int
+sfax_ctrl(struct sfax_hw *sf, u32 cmd, u_long arg)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case HW_RESET_REQ:
+ reset_speedfax(sf);
+ break;
+ case HW_ACTIVATE_IND:
+ if (arg & 1)
+ sf->aux_data &= ~SFAX_LED1_BIT;
+ if (arg & 2)
+ sf->aux_data &= ~SFAX_LED2_BIT;
+ outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
+ break;
+ case HW_DEACT_IND:
+ if (arg & 1)
+ sf->aux_data |= SFAX_LED1_BIT;
+ if (arg & 2)
+ sf->aux_data |= SFAX_LED2_BIT;
+ outb(sf->aux_data, sf->cfg + TIGER_AUX_DATA);
+ break;
+ default:
+ pr_info("%s: %s unknown command %x %lx\n",
+ sf->name, __func__, cmd, arg);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+channel_ctrl(struct sfax_hw *sf, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = MISDN_CTRL_LOOP;
+ break;
+ case MISDN_CTRL_LOOP:
+ /* cq->channel: 0 disable, 1 B1 loop 2 B2 loop, 3 both */
+ if (cq->channel < 0 || cq->channel > 3) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = sf->isac.ctrl(&sf->isac, HW_TESTLOOP, cq->channel);
+ break;
+ default:
+ pr_info("%s: unknown Op %x\n", sf->name, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+sfax_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct sfax_hw *sf = dch->hw;
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: cmd:%x %p\n", sf->name, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = sf->isac.open(&sf->isac, rq);
+ else
+ err = sf->isar.open(&sf->isar, rq);
+ if (err)
+ break;
+ if (!try_module_get(THIS_MODULE))
+ pr_info("%s: cannot get module\n", sf->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", sf->name,
+ dch->dev.id, __builtin_return_address(0));
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(sf, arg);
+ break;
+ default:
+ pr_debug("%s: unknown command %x\n", sf->name, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+static int __devinit
+init_card(struct sfax_hw *sf)
+{
+ int ret, cnt = 3;
+ u_long flags;
+
+ ret = request_irq(sf->irq, speedfax_irq, IRQF_SHARED, sf->name, sf);
+ if (ret) {
+ pr_info("%s: couldn't get interrupt %d\n", sf->name, sf->irq);
+ return ret;
+ }
+ while (cnt--) {
+ spin_lock_irqsave(&sf->lock, flags);
+ ret = sf->isac.init(&sf->isac);
+ if (ret) {
+ spin_unlock_irqrestore(&sf->lock, flags);
+ pr_info("%s: ISAC init failed with %d\n",
+ sf->name, ret);
+ break;
+ }
+ enable_hwirq(sf);
+ /* RESET Receiver and Transmitter */
+ WriteISAC_IND(sf, ISAC_CMDR, 0x41);
+ spin_unlock_irqrestore(&sf->lock, flags);
+ msleep_interruptible(10);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IRQ %d count %d\n", sf->name,
+ sf->irq, sf->irqcnt);
+ if (!sf->irqcnt) {
+ pr_info("%s: IRQ(%d) got no requests during init %d\n",
+ sf->name, sf->irq, 3 - cnt);
+ } else
+ return 0;
+ }
+ free_irq(sf->irq, sf);
+ return -EIO;
+}
+
+
+static int __devinit
+setup_speedfax(struct sfax_hw *sf)
+{
+ u_long flags;
+
+ if (!request_region(sf->cfg, 256, sf->name)) {
+ pr_info("mISDN: %s config port %x-%x already in use\n",
+ sf->name, sf->cfg, sf->cfg + 255);
+ return -EIO;
+ }
+ outb(0xff, sf->cfg);
+ outb(0, sf->cfg);
+ outb(0xdd, sf->cfg + TIGER_AUX_CTRL);
+ outb(0, sf->cfg + TIGER_AUX_IRQMASK);
+
+ sf->isac.type = IPAC_TYPE_ISAC;
+ sf->p_isac.ale = sf->cfg + SFAX_PCI_ADDR;
+ sf->p_isac.port = sf->cfg + SFAX_PCI_ISAC;
+ sf->p_isar.ale = sf->cfg + SFAX_PCI_ADDR;
+ sf->p_isar.port = sf->cfg + SFAX_PCI_ISAR;
+ ASSIGN_FUNC(IND, ISAC, sf->isac);
+ ASSIGN_FUNC(IND, ISAR, sf->isar);
+ spin_lock_irqsave(&sf->lock, flags);
+ reset_speedfax(sf);
+ disable_hwirq(sf);
+ spin_unlock_irqrestore(&sf->lock, flags);
+ return 0;
+}
+
+static void
+release_card(struct sfax_hw *card) {
+ u_long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ disable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ card->isac.release(&card->isac);
+ free_irq(card->irq, card);
+ card->isar.release(&card->isar);
+ mISDN_unregister_device(&card->isac.dch.dev);
+ release_region(card->cfg, 256);
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ sfax_cnt--;
+}
+
+static int __devinit
+setup_instance(struct sfax_hw *card)
+{
+ const struct firmware *firmware;
+ int i, err;
+ u_long flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "Speedfax.%d", sfax_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+ _set_debug(card);
+ spin_lock_init(&card->lock);
+ card->isac.hwlock = &card->lock;
+ card->isar.hwlock = &card->lock;
+ card->isar.ctrl = (void *)&sfax_ctrl;
+ card->isac.name = card->name;
+ card->isar.name = card->name;
+ card->isar.owner = THIS_MODULE;
+
+ err = request_firmware(&firmware, "isdn/ISAR.BIN", &card->pdev->dev);
+ if (err < 0) {
+ pr_info("%s: firmware request failed %d\n",
+ card->name, err);
+ goto error_fw;
+ }
+ if (debug & DEBUG_HW)
+ pr_notice("%s: got firmware %zu bytes\n",
+ card->name, firmware->size);
+
+ mISDNisac_init(&card->isac, card);
+
+ card->isac.dch.dev.D.ctrl = sfax_dctrl;
+ card->isac.dch.dev.Bprotocols =
+ mISDNisar_init(&card->isar, card);
+ for (i = 0; i < 2; i++) {
+ set_channelmap(i + 1, card->isac.dch.dev.channelmap);
+ list_add(&card->isar.ch[i].bch.ch.list,
+ &card->isac.dch.dev.bchannels);
+ }
+
+ err = setup_speedfax(card);
+ if (err)
+ goto error_setup;
+ err = card->isar.init(&card->isar);
+ if (err)
+ goto error;
+ err = mISDN_register_device(&card->isac.dch.dev,
+ &card->pdev->dev, card->name);
+ if (err)
+ goto error;
+ err = init_card(card);
+ if (err)
+ goto error_init;
+ err = card->isar.firmware(&card->isar, firmware->data, firmware->size);
+ if (!err) {
+ release_firmware(firmware);
+ sfax_cnt++;
+ pr_notice("SpeedFax %d cards installed\n", sfax_cnt);
+ return 0;
+ }
+ disable_hwirq(card);
+ free_irq(card->irq, card);
+error_init:
+ mISDN_unregister_device(&card->isac.dch.dev);
+error:
+ release_region(card->cfg, 256);
+error_setup:
+ card->isac.release(&card->isac);
+ card->isar.release(&card->isar);
+ release_firmware(firmware);
+error_fw:
+ pci_disable_device(card->pdev);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ return err;
+}
+
+static int __devinit
+sfaxpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ struct sfax_hw *card = kzalloc(sizeof(struct sfax_hw), GFP_KERNEL);
+
+ if (!card) {
+ pr_info("No memory for Speedfax+ PCI\n");
+ return err;
+ }
+ card->pdev = pdev;
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+
+ pr_notice("mISDN: Speedfax found adapter %s at %s\n",
+ (char *)ent->driver_data, pci_name(pdev));
+
+ card->cfg = pci_resource_start(pdev, 0);
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err)
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit
+sfax_remove_pci(struct pci_dev *pdev)
+{
+ struct sfax_hw *card = pci_get_drvdata(pdev);
+
+ if (card)
+ release_card(card);
+ else
+ pr_debug("%s: drvdata allready removed\n", __func__);
+}
+
+static struct pci_device_id sfaxpci_ids[] __devinitdata = {
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_SPEEDFAX_PYRAMID, PCI_SUB_ID_SEDLBAUER,
+ 0, 0, (unsigned long) "Pyramid Speedfax + PCI"
+ },
+ { PCI_VENDOR_ID_TIGERJET, PCI_DEVICE_ID_TIGERJET_100,
+ PCI_SUBVENDOR_SPEEDFAX_PCI, PCI_SUB_ID_SEDLBAUER,
+ 0, 0, (unsigned long) "Sedlbauer Speedfax + PCI"
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, sfaxpci_ids);
+
+static struct pci_driver sfaxpci_driver = {
+ .name = "speedfax+ pci",
+ .probe = sfaxpci_probe,
+ .remove = __devexit_p(sfax_remove_pci),
+ .id_table = sfaxpci_ids,
+};
+
+static int __init
+Speedfax_init(void)
+{
+ int err;
+
+ pr_notice("Sedlbauer Speedfax+ Driver Rev. %s\n",
+ SPEEDFAX_REV);
+ err = pci_register_driver(&sfaxpci_driver);
+ return err;
+}
+
+static void __exit
+Speedfax_cleanup(void)
+{
+ pci_unregister_driver(&sfaxpci_driver);
+}
+
+module_init(Speedfax_init);
+module_exit(Speedfax_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
new file mode 100644
index 00000000000..d3f1077b709
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -0,0 +1,1440 @@
+/*
+ * w6692.c mISDN driver for Winbond w6692 based cards
+ *
+ * Author Karsten Keil <kkeil@suse.de>
+ * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mISDNhw.h>
+#include "w6692.h"
+
+#define W6692_REV "2.0"
+
+#define DBUSY_TIMER_VALUE 80
+
+enum {
+ W6692_ASUS,
+ W6692_WINBOND,
+ W6692_USR
+};
+
+/* private data in the PCI devices list */
+struct w6692map {
+ u_int subtype;
+ char *name;
+};
+
+static const struct w6692map w6692_map[] =
+{
+ {W6692_ASUS, "Dynalink/AsusCom IS64PH"},
+ {W6692_WINBOND, "Winbond W6692"},
+ {W6692_USR, "USR W6692"}
+};
+
+#ifndef PCI_VENDOR_ID_USR
+#define PCI_VENDOR_ID_USR 0x16ec
+#define PCI_DEVICE_ID_USR_6692 0x3409
+#endif
+
+struct w6692_ch {
+ struct bchannel bch;
+ u32 addr;
+ struct timer_list timer;
+ u8 b_mode;
+};
+
+struct w6692_hw {
+ struct list_head list;
+ struct pci_dev *pdev;
+ char name[MISDN_MAX_IDLEN];
+ u32 irq;
+ u32 irqcnt;
+ u32 addr;
+ u32 fmask; /* feature mask - bit set per card nr */
+ int subtype;
+ spinlock_t lock; /* hw lock */
+ u8 imask;
+ u8 pctl;
+ u8 xaddr;
+ u8 xdata;
+ u8 state;
+ struct w6692_ch bc[2];
+ struct dchannel dch;
+ char log[64];
+};
+
+static LIST_HEAD(Cards);
+static DEFINE_RWLOCK(card_lock); /* protect Cards */
+
+static int w6692_cnt;
+static int debug;
+static u32 led;
+static u32 pots;
+
+static void
+_set_debug(struct w6692_hw *card)
+{
+ card->dch.debug = debug;
+ card->bc[0].bch.debug = debug;
+ card->bc[1].bch.debug = debug;
+}
+
+static int
+set_debug(const char *val, struct kernel_param *kp)
+{
+ int ret;
+ struct w6692_hw *card;
+
+ ret = param_set_uint(val, kp);
+ if (!ret) {
+ read_lock(&card_lock);
+ list_for_each_entry(card, &Cards, list)
+ _set_debug(card);
+ read_unlock(&card_lock);
+ }
+ return ret;
+}
+
+MODULE_AUTHOR("Karsten Keil");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(W6692_REV);
+module_param_call(debug, set_debug, param_get_uint, &debug, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "W6692 debug mask");
+module_param(led, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(led, "W6692 LED support bitmask (one bit per card)");
+module_param(pots, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pots, "W6692 POTS support bitmask (one bit per card)");
+
+static inline u8
+ReadW6692(struct w6692_hw *card, u8 offset)
+{
+ return inb(card->addr + offset);
+}
+
+static inline void
+WriteW6692(struct w6692_hw *card, u8 offset, u8 value)
+{
+ outb(value, card->addr + offset);
+}
+
+static inline u8
+ReadW6692B(struct w6692_ch *bc, u8 offset)
+{
+ return inb(bc->addr + offset);
+}
+
+static inline void
+WriteW6692B(struct w6692_ch *bc, u8 offset, u8 value)
+{
+ outb(value, bc->addr + offset);
+}
+
+static void
+enable_hwirq(struct w6692_hw *card)
+{
+ WriteW6692(card, W_IMASK, card->imask);
+}
+
+static void
+disable_hwirq(struct w6692_hw *card)
+{
+ WriteW6692(card, W_IMASK, 0xff);
+}
+
+static const char *W6692Ver[] = {"V00", "V01", "V10", "V11"};
+
+static void
+W6692Version(struct w6692_hw *card)
+{
+ int val;
+
+ val = ReadW6692(card, W_D_RBCH);
+ pr_notice("%s: Winbond W6692 version: %s\n", card->name,
+ W6692Ver[(val >> 6) & 3]);
+}
+
+static void
+w6692_led_handler(struct w6692_hw *card, int on)
+{
+ if ((!(card->fmask & led)) || card->subtype == W6692_USR)
+ return;
+ if (on) {
+ card->xdata &= 0xfb; /* LED ON */
+ WriteW6692(card, W_XDATA, card->xdata);
+ } else {
+ card->xdata |= 0x04; /* LED OFF */
+ WriteW6692(card, W_XDATA, card->xdata);
+ }
+}
+
+static void
+ph_command(struct w6692_hw *card, u8 cmd)
+{
+ pr_debug("%s: ph_command %x\n", card->name, cmd);
+ WriteW6692(card, W_CIX, cmd);
+}
+
+static void
+W6692_new_ph(struct w6692_hw *card)
+{
+ if (card->state == W_L1CMD_RST)
+ ph_command(card, W_L1CMD_DRC);
+ schedule_event(&card->dch, FLG_PHCHANGE);
+}
+
+static void
+W6692_ph_bh(struct dchannel *dch)
+{
+ struct w6692_hw *card = dch->hw;
+
+ switch (card->state) {
+ case W_L1CMD_RST:
+ dch->state = 0;
+ l1_event(dch->l1, HW_RESET_IND);
+ break;
+ case W_L1IND_CD:
+ dch->state = 3;
+ l1_event(dch->l1, HW_DEACT_CNF);
+ break;
+ case W_L1IND_DRD:
+ dch->state = 3;
+ l1_event(dch->l1, HW_DEACT_IND);
+ break;
+ case W_L1IND_CE:
+ dch->state = 4;
+ l1_event(dch->l1, HW_POWERUP_IND);
+ break;
+ case W_L1IND_LD:
+ if (dch->state <= 5) {
+ dch->state = 5;
+ l1_event(dch->l1, ANYSIGNAL);
+ } else {
+ dch->state = 8;
+ l1_event(dch->l1, LOSTFRAMING);
+ }
+ break;
+ case W_L1IND_ARD:
+ dch->state = 6;
+ l1_event(dch->l1, INFO2);
+ break;
+ case W_L1IND_AI8:
+ dch->state = 7;
+ l1_event(dch->l1, INFO4_P8);
+ break;
+ case W_L1IND_AI10:
+ dch->state = 7;
+ l1_event(dch->l1, INFO4_P10);
+ break;
+ default:
+ pr_debug("%s: TE unknown state %02x dch state %02x\n",
+ card->name, card->state, dch->state);
+ break;
+ }
+ pr_debug("%s: TE newstate %02x\n", card->name, dch->state);
+}
+
+static void
+W6692_empty_Dfifo(struct w6692_hw *card, int count)
+{
+ struct dchannel *dch = &card->dch;
+ u8 *ptr;
+
+ pr_debug("%s: empty_Dfifo %d\n", card->name, count);
+ if (!dch->rx_skb) {
+ dch->rx_skb = mI_alloc_skb(card->dch.maxlen, GFP_ATOMIC);
+ if (!dch->rx_skb) {
+ pr_info("%s: D receive out of memory\n", card->name);
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+ return;
+ }
+ }
+ if ((dch->rx_skb->len + count) >= dch->maxlen) {
+ pr_debug("%s: empty_Dfifo overrun %d\n", card->name,
+ dch->rx_skb->len + count);
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+ return;
+ }
+ ptr = skb_put(dch->rx_skb, count);
+ insb(card->addr + W_D_RFIFO, ptr, count);
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK);
+ if (debug & DEBUG_HW_DFIFO) {
+ snprintf(card->log, 63, "D-recv %s %d ",
+ card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+W6692_fill_Dfifo(struct w6692_hw *card)
+{
+ struct dchannel *dch = &card->dch;
+ int count;
+ u8 *ptr;
+ u8 cmd = W_D_CMDR_XMS;
+
+ pr_debug("%s: fill_Dfifo\n", card->name);
+ if (!dch->tx_skb)
+ return;
+ count = dch->tx_skb->len - dch->tx_idx;
+ if (count <= 0)
+ return;
+ if (count > W_D_FIFO_THRESH)
+ count = W_D_FIFO_THRESH;
+ else
+ cmd |= W_D_CMDR_XME;
+ ptr = dch->tx_skb->data + dch->tx_idx;
+ dch->tx_idx += count;
+ outsb(card->addr + W_D_XFIFO, ptr, count);
+ WriteW6692(card, W_D_CMDR, cmd);
+ if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) {
+ pr_debug("%s: fill_Dfifo dbusytimer running\n", card->name);
+ del_timer(&dch->timer);
+ }
+ init_timer(&dch->timer);
+ dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+ add_timer(&dch->timer);
+ if (debug & DEBUG_HW_DFIFO) {
+ snprintf(card->log, 63, "D-send %s %d ",
+ card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+d_retransmit(struct w6692_hw *card)
+{
+ struct dchannel *dch = &card->dch;
+
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+ del_timer(&dch->timer);
+#ifdef FIXME
+ if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags))
+ dchannel_sched_event(dch, D_CLEARBUSY);
+#endif
+ if (test_bit(FLG_TX_BUSY, &dch->Flags)) {
+ /* Restart frame */
+ dch->tx_idx = 0;
+ W6692_fill_Dfifo(card);
+ } else if (dch->tx_skb) { /* should not happen */
+ pr_info("%s: %s without TX_BUSY\n", card->name, __func__);
+ test_and_set_bit(FLG_TX_BUSY, &dch->Flags);
+ dch->tx_idx = 0;
+ W6692_fill_Dfifo(card);
+ } else {
+ pr_info("%s: XDU no TX_BUSY\n", card->name);
+ if (get_next_dframe(dch))
+ W6692_fill_Dfifo(card);
+ }
+}
+
+static void
+handle_rxD(struct w6692_hw *card) {
+ u8 stat;
+ int count;
+
+ stat = ReadW6692(card, W_D_RSTA);
+ if (stat & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) {
+ if (stat & W_D_RSTA_RDOV) {
+ pr_debug("%s: D-channel RDOV\n", card->name);
+#ifdef ERROR_STATISTIC
+ card->dch.err_rx++;
+#endif
+ }
+ if (stat & W_D_RSTA_CRCE) {
+ pr_debug("%s: D-channel CRC error\n", card->name);
+#ifdef ERROR_STATISTIC
+ card->dch.err_crc++;
+#endif
+ }
+ if (stat & W_D_RSTA_RMB) {
+ pr_debug("%s: D-channel ABORT\n", card->name);
+#ifdef ERROR_STATISTIC
+ card->dch.err_rx++;
+#endif
+ }
+ if (card->dch.rx_skb)
+ dev_kfree_skb(card->dch.rx_skb);
+ card->dch.rx_skb = NULL;
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST);
+ } else {
+ count = ReadW6692(card, W_D_RBCL) & (W_D_FIFO_THRESH - 1);
+ if (count == 0)
+ count = W_D_FIFO_THRESH;
+ W6692_empty_Dfifo(card, count);
+ recv_Dchannel(&card->dch);
+ }
+}
+
+static void
+handle_txD(struct w6692_hw *card) {
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &card->dch.Flags))
+ del_timer(&card->dch.timer);
+ if (card->dch.tx_skb && card->dch.tx_idx < card->dch.tx_skb->len) {
+ W6692_fill_Dfifo(card);
+ } else {
+ if (card->dch.tx_skb)
+ dev_kfree_skb(card->dch.tx_skb);
+ if (get_next_dframe(&card->dch))
+ W6692_fill_Dfifo(card);
+ }
+}
+
+static void
+handle_statusD(struct w6692_hw *card)
+{
+ struct dchannel *dch = &card->dch;
+ u8 exval, v1, cir;
+
+ exval = ReadW6692(card, W_D_EXIR);
+
+ pr_debug("%s: D_EXIR %02x\n", card->name, exval);
+ if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) {
+ /* Transmit underrun/collision */
+ pr_debug("%s: D-channel underrun/collision\n", card->name);
+#ifdef ERROR_STATISTIC
+ dch->err_tx++;
+#endif
+ d_retransmit(card);
+ }
+ if (exval & W_D_EXI_RDOV) { /* RDOV */
+ pr_debug("%s: D-channel RDOV\n", card->name);
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST);
+ }
+ if (exval & W_D_EXI_TIN2) /* TIN2 - never */
+ pr_debug("%s: spurious TIN2 interrupt\n", card->name);
+ if (exval & W_D_EXI_MOC) { /* MOC - not supported */
+ v1 = ReadW6692(card, W_MOSR);
+ pr_debug("%s: spurious MOC interrupt MOSR %02x\n",
+ card->name, v1);
+ }
+ if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */
+ cir = ReadW6692(card, W_CIR);
+ pr_debug("%s: ISC CIR %02X\n", card->name, cir);
+ if (cir & W_CIR_ICC) {
+ v1 = cir & W_CIR_COD_MASK;
+ pr_debug("%s: ph_state_change %x -> %x\n", card->name,
+ dch->state, v1);
+ card->state = v1;
+ if (card->fmask & led) {
+ switch (v1) {
+ case W_L1IND_AI8:
+ case W_L1IND_AI10:
+ w6692_led_handler(card, 1);
+ break;
+ default:
+ w6692_led_handler(card, 0);
+ break;
+ }
+ }
+ W6692_new_ph(card);
+ }
+ if (cir & W_CIR_SCC) {
+ v1 = ReadW6692(card, W_SQR);
+ pr_debug("%s: SCC SQR %02X\n", card->name, v1);
+ }
+ }
+ if (exval & W_D_EXI_WEXP)
+ pr_debug("%s: spurious WEXP interrupt!\n", card->name);
+ if (exval & W_D_EXI_TEXP)
+ pr_debug("%s: spurious TEXP interrupt!\n", card->name);
+}
+
+static void
+W6692_empty_Bfifo(struct w6692_ch *wch, int count)
+{
+ struct w6692_hw *card = wch->bch.hw;
+ u8 *ptr;
+
+ pr_debug("%s: empty_Bfifo %d\n", card->name, count);
+ if (unlikely(wch->bch.state == ISDN_P_NONE)) {
+ pr_debug("%s: empty_Bfifo ISDN_P_NONE\n", card->name);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+ if (wch->bch.rx_skb)
+ skb_trim(wch->bch.rx_skb, 0);
+ return;
+ }
+ if (!wch->bch.rx_skb) {
+ wch->bch.rx_skb = mI_alloc_skb(wch->bch.maxlen, GFP_ATOMIC);
+ if (unlikely(!wch->bch.rx_skb)) {
+ pr_info("%s: B receive out of memory\n", card->name);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
+ W_B_CMDR_RACT);
+ return;
+ }
+ }
+ if (wch->bch.rx_skb->len + count > wch->bch.maxlen) {
+ pr_debug("%s: empty_Bfifo incoming packet too large\n",
+ card->name);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+ skb_trim(wch->bch.rx_skb, 0);
+ return;
+ }
+ ptr = skb_put(wch->bch.rx_skb, count);
+ insb(wch->addr + W_B_RFIFO, ptr, count);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+ if (debug & DEBUG_HW_DFIFO) {
+ snprintf(card->log, 63, "B%1d-recv %s %d ",
+ wch->bch.nr, card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static void
+W6692_fill_Bfifo(struct w6692_ch *wch)
+{
+ struct w6692_hw *card = wch->bch.hw;
+ int count;
+ u8 *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS;
+
+ pr_debug("%s: fill Bfifo\n", card->name);
+ if (!wch->bch.tx_skb)
+ return;
+ count = wch->bch.tx_skb->len - wch->bch.tx_idx;
+ if (count <= 0)
+ return;
+ ptr = wch->bch.tx_skb->data + wch->bch.tx_idx;
+ if (count > W_B_FIFO_THRESH)
+ count = W_B_FIFO_THRESH;
+ else if (test_bit(FLG_HDLC, &wch->bch.Flags))
+ cmd |= W_B_CMDR_XME;
+
+ pr_debug("%s: fill Bfifo%d/%d\n", card->name,
+ count, wch->bch.tx_idx);
+ wch->bch.tx_idx += count;
+ outsb(wch->addr + W_B_XFIFO, ptr, count);
+ WriteW6692B(wch, W_B_CMDR, cmd);
+ if (debug & DEBUG_HW_DFIFO) {
+ snprintf(card->log, 63, "B%1d-send %s %d ",
+ wch->bch.nr, card->name, count);
+ print_hex_dump_bytes(card->log, DUMP_PREFIX_OFFSET, ptr, count);
+ }
+}
+
+static int
+setvolume(struct w6692_ch *wch, int mic, struct sk_buff *skb)
+{
+ struct w6692_hw *card = wch->bch.hw;
+ u16 *vol = (u16 *)skb->data;
+ u8 val;
+
+ if ((!(card->fmask & pots)) ||
+ !test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ return -ENODEV;
+ if (skb->len < 2)
+ return -EINVAL;
+ if (*vol > 7)
+ return -EINVAL;
+ val = *vol & 7;
+ val = 7 - val;
+ if (mic) {
+ val <<= 3;
+ card->xaddr &= 0xc7;
+ } else {
+ card->xaddr &= 0xf8;
+ }
+ card->xaddr |= val;
+ WriteW6692(card, W_XADDR, card->xaddr);
+ return 0;
+}
+
+static int
+enable_pots(struct w6692_ch *wch)
+{
+ struct w6692_hw *card = wch->bch.hw;
+
+ if ((!(card->fmask & pots)) ||
+ !test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ return -ENODEV;
+ wch->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0;
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+ card->pctl |= ((wch->bch.nr & 2) ? W_PCTL_PCX : 0);
+ WriteW6692(card, W_PCTL, card->pctl);
+ return 0;
+}
+
+static int
+disable_pots(struct w6692_ch *wch)
+{
+ struct w6692_hw *card = wch->bch.hw;
+
+ if (!(card->fmask & pots))
+ return -ENODEV;
+ wch->b_mode &= ~(W_B_MODE_EPCM | W_B_MODE_BSW0);
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
+ W_B_CMDR_XRST);
+ return 0;
+}
+
+static int
+w6692_mode(struct w6692_ch *wch, u32 pr)
+{
+ struct w6692_hw *card;
+
+ card = wch->bch.hw;
+ pr_debug("%s: B%d protocol %x-->%x\n", card->name,
+ wch->bch.nr, wch->bch.state, pr);
+ switch (pr) {
+ case ISDN_P_NONE:
+ if ((card->fmask & pots) && (wch->b_mode & W_B_MODE_EPCM))
+ disable_pots(wch);
+ wch->b_mode = 0;
+ mISDN_clear_bchannel(&wch->bch);
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+ test_and_clear_bit(FLG_HDLC, &wch->bch.Flags);
+ test_and_clear_bit(FLG_TRANSPARENT, &wch->bch.Flags);
+ break;
+ case ISDN_P_B_RAW:
+ wch->b_mode = W_B_MODE_MMS;
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_EXIM, 0);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
+ W_B_CMDR_XRST);
+ test_and_set_bit(FLG_TRANSPARENT, &wch->bch.Flags);
+ break;
+ case ISDN_P_B_HDLC:
+ wch->b_mode = W_B_MODE_ITF;
+ WriteW6692B(wch, W_B_MODE, wch->b_mode);
+ WriteW6692B(wch, W_B_ADM1, 0xff);
+ WriteW6692B(wch, W_B_ADM2, 0xff);
+ WriteW6692B(wch, W_B_EXIM, 0);
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT |
+ W_B_CMDR_XRST);
+ test_and_set_bit(FLG_HDLC, &wch->bch.Flags);
+ break;
+ default:
+ pr_info("%s: protocol %x not known\n", card->name, pr);
+ return -ENOPROTOOPT;
+ }
+ wch->bch.state = pr;
+ return 0;
+}
+
+static void
+send_next(struct w6692_ch *wch)
+{
+ if (wch->bch.tx_skb && wch->bch.tx_idx < wch->bch.tx_skb->len)
+ W6692_fill_Bfifo(wch);
+ else {
+ if (wch->bch.tx_skb) {
+ /* send confirm, on trans, free on hdlc. */
+ if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ confirm_Bsend(&wch->bch);
+ dev_kfree_skb(wch->bch.tx_skb);
+ }
+ if (get_next_bframe(&wch->bch))
+ W6692_fill_Bfifo(wch);
+ }
+}
+
+static void
+W6692B_interrupt(struct w6692_hw *card, int ch)
+{
+ struct w6692_ch *wch = &card->bc[ch];
+ int count;
+ u8 stat, star = 0;
+
+ stat = ReadW6692B(wch, W_B_EXIR);
+ pr_debug("%s: B%d EXIR %02x\n", card->name, wch->bch.nr, stat);
+ if (stat & W_B_EXI_RME) {
+ star = ReadW6692B(wch, W_B_STAR);
+ if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) {
+ if ((star & W_B_STAR_RDOV) &&
+ test_bit(FLG_ACTIVE, &wch->bch.Flags)) {
+ pr_debug("%s: B%d RDOV proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_rdo++;
+#endif
+ }
+ if (test_bit(FLG_HDLC, &wch->bch.Flags)) {
+ if (star & W_B_STAR_CRCE) {
+ pr_debug("%s: B%d CRC error\n",
+ card->name, wch->bch.nr);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_crc++;
+#endif
+ }
+ if (star & W_B_STAR_RMB) {
+ pr_debug("%s: B%d message abort\n",
+ card->name, wch->bch.nr);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_inv++;
+#endif
+ }
+ }
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
+ W_B_CMDR_RRST | W_B_CMDR_RACT);
+ if (wch->bch.rx_skb)
+ skb_trim(wch->bch.rx_skb, 0);
+ } else {
+ count = ReadW6692B(wch, W_B_RBCL) &
+ (W_B_FIFO_THRESH - 1);
+ if (count == 0)
+ count = W_B_FIFO_THRESH;
+ W6692_empty_Bfifo(wch, count);
+ recv_Bchannel(&wch->bch, 0);
+ }
+ }
+ if (stat & W_B_EXI_RMR) {
+ if (!(stat & W_B_EXI_RME))
+ star = ReadW6692B(wch, W_B_STAR);
+ if (star & W_B_STAR_RDOV) {
+ pr_debug("%s: B%d RDOV proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_rdo++;
+#endif
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
+ W_B_CMDR_RRST | W_B_CMDR_RACT);
+ } else {
+ W6692_empty_Bfifo(wch, W_B_FIFO_THRESH);
+ if (test_bit(FLG_TRANSPARENT, &wch->bch.Flags) &&
+ wch->bch.rx_skb && (wch->bch.rx_skb->len > 0))
+ recv_Bchannel(&wch->bch, 0);
+ }
+ }
+ if (stat & W_B_EXI_RDOV) {
+ /* only if it is not handled yet */
+ if (!(star & W_B_STAR_RDOV)) {
+ pr_debug("%s: B%d RDOV IRQ proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_rdo++;
+#endif
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_RACK |
+ W_B_CMDR_RRST | W_B_CMDR_RACT);
+ }
+ }
+ if (stat & W_B_EXI_XFR) {
+ if (!(stat & (W_B_EXI_RME | W_B_EXI_RMR))) {
+ star = ReadW6692B(wch, W_B_STAR);
+ pr_debug("%s: B%d star %02x\n", card->name,
+ wch->bch.nr, star);
+ }
+ if (star & W_B_STAR_XDOW) {
+ pr_debug("%s: B%d XDOW proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_xdu++;
+#endif
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST |
+ W_B_CMDR_RACT);
+ /* resend */
+ if (wch->bch.tx_skb) {
+ if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ wch->bch.tx_idx = 0;
+ }
+ }
+ send_next(wch);
+ if (stat & W_B_EXI_XDUN)
+ return; /* handle XDOW only once */
+ }
+ if (stat & W_B_EXI_XDUN) {
+ pr_debug("%s: B%d XDUN proto=%x\n", card->name,
+ wch->bch.nr, wch->bch.state);
+#ifdef ERROR_STATISTIC
+ wch->bch.err_xdu++;
+#endif
+ WriteW6692B(wch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
+ /* resend */
+ if (wch->bch.tx_skb) {
+ if (!test_bit(FLG_TRANSPARENT, &wch->bch.Flags))
+ wch->bch.tx_idx = 0;
+ }
+ send_next(wch);
+ }
+}
+
+static irqreturn_t
+w6692_irq(int intno, void *dev_id)
+{
+ struct w6692_hw *card = dev_id;
+ u8 ista;
+
+ spin_lock(&card->lock);
+ ista = ReadW6692(card, W_ISTA);
+ if ((ista | card->imask) == card->imask) {
+ /* possible a shared IRQ reqest */
+ spin_unlock(&card->lock);
+ return IRQ_NONE;
+ }
+ card->irqcnt++;
+ pr_debug("%s: ista %02x\n", card->name, ista);
+ ista &= ~card->imask;
+ if (ista & W_INT_B1_EXI)
+ W6692B_interrupt(card, 0);
+ if (ista & W_INT_B2_EXI)
+ W6692B_interrupt(card, 1);
+ if (ista & W_INT_D_RME)
+ handle_rxD(card);
+ if (ista & W_INT_D_RMR)
+ W6692_empty_Dfifo(card, W_D_FIFO_THRESH);
+ if (ista & W_INT_D_XFR)
+ handle_txD(card);
+ if (ista & W_INT_D_EXI)
+ handle_statusD(card);
+ if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */
+ pr_debug("%s: W6692 spurious XINT!\n", card->name);
+/* End IRQ Handler */
+ spin_unlock(&card->lock);
+ return IRQ_HANDLED;
+}
+
+static void
+dbusy_timer_handler(struct dchannel *dch)
+{
+ struct w6692_hw *card = dch->hw;
+ int rbch, star;
+ u_long flags;
+
+ if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) {
+ spin_lock_irqsave(&card->lock, flags);
+ rbch = ReadW6692(card, W_D_RBCH);
+ star = ReadW6692(card, W_D_STAR);
+ pr_debug("%s: D-Channel Busy RBCH %02x STAR %02x\n",
+ card->name, rbch, star);
+ if (star & W_D_STAR_XBZ) /* D-Channel Busy */
+ test_and_set_bit(FLG_L1_BUSY, &dch->Flags);
+ else {
+ /* discard frame; reset transceiver */
+ test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags);
+ if (dch->tx_idx)
+ dch->tx_idx = 0;
+ else
+ pr_info("%s: W6692 D-Channel Busy no tx_idx\n",
+ card->name);
+ /* Transmitter reset */
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+ }
+}
+
+void initW6692(struct w6692_hw *card)
+{
+ u8 val;
+
+ card->dch.timer.function = (void *)dbusy_timer_handler;
+ card->dch.timer.data = (u_long)&card->dch;
+ init_timer(&card->dch.timer);
+ w6692_mode(&card->bc[0], ISDN_P_NONE);
+ w6692_mode(&card->bc[1], ISDN_P_NONE);
+ WriteW6692(card, W_D_CTL, 0x00);
+ disable_hwirq(card);
+ WriteW6692(card, W_D_SAM, 0xff);
+ WriteW6692(card, W_D_TAM, 0xff);
+ WriteW6692(card, W_D_MODE, W_D_MODE_RACT);
+ card->state = W_L1CMD_RST;
+ ph_command(card, W_L1CMD_RST);
+ ph_command(card, W_L1CMD_ECK);
+ /* enable all IRQ but extern */
+ card->imask = 0x18;
+ WriteW6692(card, W_D_EXIM, 0x00);
+ WriteW6692B(&card->bc[0], W_B_EXIM, 0);
+ WriteW6692B(&card->bc[1], W_B_EXIM, 0);
+ /* Reset D-chan receiver and transmitter */
+ WriteW6692(card, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST);
+ /* Reset B-chan receiver and transmitter */
+ WriteW6692B(&card->bc[0], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+ WriteW6692B(&card->bc[1], W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST);
+ /* enable peripheral */
+ if (card->subtype == W6692_USR) {
+ /* seems that USR implemented some power control features
+ * Pin 79 is connected to the oscilator circuit so we
+ * have to handle it here
+ */
+ card->pctl = 0x80;
+ card->xdata = 0;
+ WriteW6692(card, W_PCTL, card->pctl);
+ WriteW6692(card, W_XDATA, card->xdata);
+ } else {
+ card->pctl = W_PCTL_OE5 | W_PCTL_OE4 | W_PCTL_OE2 |
+ W_PCTL_OE1 | W_PCTL_OE0;
+ card->xaddr = 0x00;/* all sw off */
+ if (card->fmask & pots)
+ card->xdata |= 0x06; /* POWER UP/ LED OFF / ALAW */
+ if (card->fmask & led)
+ card->xdata |= 0x04; /* LED OFF */
+ if ((card->fmask & pots) || (card->fmask & led)) {
+ WriteW6692(card, W_PCTL, card->pctl);
+ WriteW6692(card, W_XADDR, card->xaddr);
+ WriteW6692(card, W_XDATA, card->xdata);
+ val = ReadW6692(card, W_XADDR);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: W_XADDR=%02x\n",
+ card->name, val);
+ }
+ }
+}
+
+static void
+reset_w6692(struct w6692_hw *card)
+{
+ WriteW6692(card, W_D_CTL, W_D_CTL_SRST);
+ mdelay(10);
+ WriteW6692(card, W_D_CTL, 0);
+}
+
+static int
+init_card(struct w6692_hw *card)
+{
+ int cnt = 3;
+ u_long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ disable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (request_irq(card->irq, w6692_irq, IRQF_SHARED, card->name, card)) {
+ pr_info("%s: couldn't get interrupt %d\n", card->name,
+ card->irq);
+ return -EIO;
+ }
+ while (cnt--) {
+ spin_lock_irqsave(&card->lock, flags);
+ initW6692(card);
+ enable_hwirq(card);
+ spin_unlock_irqrestore(&card->lock, flags);
+ /* Timeout 10ms */
+ msleep_interruptible(10);
+ if (debug & DEBUG_HW)
+ pr_notice("%s: IRQ %d count %d\n", card->name,
+ card->irq, card->irqcnt);
+ if (!card->irqcnt) {
+ pr_info("%s: IRQ(%d) getting no IRQs during init %d\n",
+ card->name, card->irq, 3 - cnt);
+ reset_w6692(card);
+ } else
+ return 0;
+ }
+ free_irq(card->irq, card);
+ return -EIO;
+}
+
+static int
+w6692_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch);
+ struct w6692_hw *card = bch->hw;
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ ret = bchannel_senddata(bch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ ret = 0;
+ W6692_fill_Bfifo(bc);
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(&card->lock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags))
+ ret = w6692_mode(bc, ch->protocol);
+ else
+ ret = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+ if (!ret)
+ _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ break;
+ case PH_DEACTIVATE_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_clear_bchannel(bch);
+ w6692_mode(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0,
+ NULL, GFP_KERNEL);
+ ret = 0;
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x,%x)\n",
+ card->name, __func__, hh->prim, hh->id);
+ ret = -EINVAL;
+ }
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ /* Nothing implemented yet */
+ case MISDN_CTRL_FILL_EMPTY:
+ default:
+ pr_info("%s: unknown Op %x\n", __func__, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+open_bchannel(struct w6692_hw *card, struct channel_req *rq)
+{
+ struct bchannel *bch;
+
+ if (rq->adr.channel > 2)
+ return -EINVAL;
+ if (rq->protocol == ISDN_P_NONE)
+ return -EINVAL;
+ bch = &card->bc[rq->adr.channel - 1].bch;
+ if (test_and_set_bit(FLG_OPEN, &bch->Flags))
+ return -EBUSY; /* b-channel can be only open once */
+ test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
+ bch->ch.protocol = rq->protocol;
+ rq->ch = &bch->ch;
+ return 0;
+}
+
+static int
+channel_ctrl(struct w6692_hw *card, struct mISDN_ctrl_req *cq)
+{
+ int ret = 0;
+
+ switch (cq->op) {
+ case MISDN_CTRL_GETOP:
+ cq->op = 0;
+ break;
+ default:
+ pr_info("%s: unknown CTRL OP %x\n", card->name, cq->op);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int
+w6692_bctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct bchannel *bch = container_of(ch, struct bchannel, ch);
+ struct w6692_ch *bc = container_of(bch, struct w6692_ch, bch);
+ struct w6692_hw *card = bch->hw;
+ int ret = -EINVAL;
+ u_long flags;
+
+ pr_debug("%s: %s cmd:%x %p\n", card->name, __func__, cmd, arg);
+ switch (cmd) {
+ case CLOSE_CHANNEL:
+ test_and_clear_bit(FLG_OPEN, &bch->Flags);
+ if (test_bit(FLG_ACTIVE, &bch->Flags)) {
+ spin_lock_irqsave(&card->lock, flags);
+ mISDN_freebchannel(bch);
+ w6692_mode(bc, ISDN_P_NONE);
+ spin_unlock_irqrestore(&card->lock, flags);
+ } else {
+ skb_queue_purge(&bch->rqueue);
+ bch->rcount = 0;
+ }
+ ch->protocol = ISDN_P_NONE;
+ ch->peer = NULL;
+ module_put(THIS_MODULE);
+ ret = 0;
+ break;
+ case CONTROL_CHANNEL:
+ ret = channel_bctrl(bch, arg);
+ break;
+ default:
+ pr_info("%s: %s unknown prim(%x)\n",
+ card->name, __func__, cmd);
+ }
+ return ret;
+}
+
+static int
+w6692_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
+ int ret = -EINVAL;
+ struct mISDNhead *hh = mISDN_HEAD_P(skb);
+ u32 id;
+ u_long flags;
+
+ switch (hh->prim) {
+ case PH_DATA_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ ret = dchannel_senddata(dch, skb);
+ if (ret > 0) { /* direct TX */
+ id = hh->id; /* skb can be freed */
+ W6692_fill_Dfifo(card);
+ ret = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+ queue_ch_frame(ch, PH_DATA_CNF, id, NULL);
+ } else
+ spin_unlock_irqrestore(&card->lock, flags);
+ return ret;
+ case PH_ACTIVATE_REQ:
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ case PH_DEACTIVATE_REQ:
+ test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags);
+ ret = l1_event(dch->l1, hh->prim);
+ break;
+ }
+
+ if (!ret)
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+static int
+w6692_l1callback(struct dchannel *dch, u32 cmd)
+{
+ struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
+ u_long flags;
+
+ pr_debug("%s: cmd(%x) state(%02x)\n", card->name, cmd, card->state);
+ switch (cmd) {
+ case INFO3_P8:
+ spin_lock_irqsave(&card->lock, flags);
+ ph_command(card, W_L1CMD_AR8);
+ spin_unlock_irqrestore(&card->lock, flags);
+ break;
+ case INFO3_P10:
+ spin_lock_irqsave(&card->lock, flags);
+ ph_command(card, W_L1CMD_AR10);
+ spin_unlock_irqrestore(&card->lock, flags);
+ break;
+ case HW_RESET_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ if (card->state != W_L1IND_DRD)
+ ph_command(card, W_L1CMD_RST);
+ ph_command(card, W_L1CMD_ECK);
+ spin_unlock_irqrestore(&card->lock, flags);
+ break;
+ case HW_DEACT_REQ:
+ skb_queue_purge(&dch->squeue);
+ if (dch->tx_skb) {
+ dev_kfree_skb(dch->tx_skb);
+ dch->tx_skb = NULL;
+ }
+ dch->tx_idx = 0;
+ if (dch->rx_skb) {
+ dev_kfree_skb(dch->rx_skb);
+ dch->rx_skb = NULL;
+ }
+ test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
+ if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
+ del_timer(&dch->timer);
+ break;
+ case HW_POWERUP_REQ:
+ spin_lock_irqsave(&card->lock, flags);
+ ph_command(card, W_L1CMD_ECK);
+ spin_unlock_irqrestore(&card->lock, flags);
+ break;
+ case PH_ACTIVATE_IND:
+ test_and_set_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ case PH_DEACTIVATE_IND:
+ test_and_clear_bit(FLG_ACTIVE, &dch->Flags);
+ _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL,
+ GFP_ATOMIC);
+ break;
+ default:
+ pr_debug("%s: %s unknown command %x\n", card->name,
+ __func__, cmd);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+open_dchannel(struct w6692_hw *card, struct channel_req *rq)
+{
+ pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__,
+ card->dch.dev.id, __builtin_return_address(1));
+ if (rq->protocol != ISDN_P_TE_S0)
+ return -EINVAL;
+ if (rq->adr.channel == 1)
+ /* E-Channel not supported */
+ return -EINVAL;
+ rq->ch = &card->dch.dev.D;
+ rq->ch->protocol = rq->protocol;
+ if (card->dch.state == 7)
+ _queue_data(rq->ch, PH_ACTIVATE_IND, MISDN_ID_ANY,
+ 0, NULL, GFP_KERNEL);
+ return 0;
+}
+
+static int
+w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
+{
+ struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D);
+ struct dchannel *dch = container_of(dev, struct dchannel, dev);
+ struct w6692_hw *card = container_of(dch, struct w6692_hw, dch);
+ struct channel_req *rq;
+ int err = 0;
+
+ pr_debug("%s: DCTRL: %x %p\n", card->name, cmd, arg);
+ switch (cmd) {
+ case OPEN_CHANNEL:
+ rq = arg;
+ if (rq->protocol == ISDN_P_TE_S0)
+ err = open_dchannel(card, rq);
+ else
+ err = open_bchannel(card, rq);
+ if (err)
+ break;
+ if (!try_module_get(THIS_MODULE))
+ pr_info("%s: cannot get module\n", card->name);
+ break;
+ case CLOSE_CHANNEL:
+ pr_debug("%s: dev(%d) close from %p\n", card->name,
+ dch->dev.id, __builtin_return_address(0));
+ module_put(THIS_MODULE);
+ break;
+ case CONTROL_CHANNEL:
+ err = channel_ctrl(card, arg);
+ break;
+ default:
+ pr_debug("%s: unknown DCTRL command %x\n", card->name, cmd);
+ return -EINVAL;
+ }
+ return err;
+}
+
+static int
+setup_w6692(struct w6692_hw *card)
+{
+ u32 val;
+
+ if (!request_region(card->addr, 256, card->name)) {
+ pr_info("%s: config port %x-%x already in use\n", card->name,
+ card->addr, card->addr + 255);
+ return -EIO;
+ }
+ W6692Version(card);
+ card->bc[0].addr = card->addr;
+ card->bc[1].addr = card->addr + 0x40;
+ val = ReadW6692(card, W_ISTA);
+ if (debug & DEBUG_HW)
+ pr_notice("%s ISTA=%02x\n", card->name, val);
+ val = ReadW6692(card, W_IMASK);
+ if (debug & DEBUG_HW)
+ pr_notice("%s IMASK=%02x\n", card->name, val);
+ val = ReadW6692(card, W_D_EXIR);
+ if (debug & DEBUG_HW)
+ pr_notice("%s D_EXIR=%02x\n", card->name, val);
+ val = ReadW6692(card, W_D_EXIM);
+ if (debug & DEBUG_HW)
+ pr_notice("%s D_EXIM=%02x\n", card->name, val);
+ val = ReadW6692(card, W_D_RSTA);
+ if (debug & DEBUG_HW)
+ pr_notice("%s D_RSTA=%02x\n", card->name, val);
+ return 0;
+}
+
+static void
+release_card(struct w6692_hw *card)
+{
+ u_long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ disable_hwirq(card);
+ w6692_mode(&card->bc[0], ISDN_P_NONE);
+ w6692_mode(&card->bc[1], ISDN_P_NONE);
+ if ((card->fmask & led) || card->subtype == W6692_USR) {
+ card->xdata |= 0x04; /* LED OFF */
+ WriteW6692(card, W_XDATA, card->xdata);
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+ free_irq(card->irq, card);
+ l1_event(card->dch.l1, CLOSE_CHANNEL);
+ mISDN_unregister_device(&card->dch.dev);
+ release_region(card->addr, 256);
+ mISDN_freebchannel(&card->bc[1].bch);
+ mISDN_freebchannel(&card->bc[0].bch);
+ mISDN_freedchannel(&card->dch);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ pci_disable_device(card->pdev);
+ pci_set_drvdata(card->pdev, NULL);
+ kfree(card);
+}
+
+static int
+setup_instance(struct w6692_hw *card)
+{
+ int i, err;
+ u_long flags;
+
+ snprintf(card->name, MISDN_MAX_IDLEN - 1, "w6692.%d", w6692_cnt + 1);
+ write_lock_irqsave(&card_lock, flags);
+ list_add_tail(&card->list, &Cards);
+ write_unlock_irqrestore(&card_lock, flags);
+ card->fmask = (1 << w6692_cnt);
+ _set_debug(card);
+ spin_lock_init(&card->lock);
+ mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, W6692_ph_bh);
+ card->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0);
+ card->dch.dev.D.send = w6692_l2l1D;
+ card->dch.dev.D.ctrl = w6692_dctrl;
+ card->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
+ (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
+ card->dch.hw = card;
+ card->dch.dev.nrbchan = 2;
+ for (i = 0; i < 2; i++) {
+ mISDN_initbchannel(&card->bc[i].bch, MAX_DATA_MEM);
+ card->bc[i].bch.hw = card;
+ card->bc[i].bch.nr = i + 1;
+ card->bc[i].bch.ch.nr = i + 1;
+ card->bc[i].bch.ch.send = w6692_l2l1B;
+ card->bc[i].bch.ch.ctrl = w6692_bctrl;
+ set_channelmap(i + 1, card->dch.dev.channelmap);
+ list_add(&card->bc[i].bch.ch.list, &card->dch.dev.bchannels);
+ }
+ err = setup_w6692(card);
+ if (err)
+ goto error_setup;
+ err = mISDN_register_device(&card->dch.dev, &card->pdev->dev,
+ card->name);
+ if (err)
+ goto error_reg;
+ err = init_card(card);
+ if (err)
+ goto error_init;
+ err = create_l1(&card->dch, w6692_l1callback);
+ if (!err) {
+ w6692_cnt++;
+ pr_notice("W6692 %d cards installed\n", w6692_cnt);
+ return 0;
+ }
+
+ free_irq(card->irq, card);
+error_init:
+ mISDN_unregister_device(&card->dch.dev);
+error_reg:
+ release_region(card->addr, 256);
+error_setup:
+ mISDN_freebchannel(&card->bc[1].bch);
+ mISDN_freebchannel(&card->bc[0].bch);
+ mISDN_freedchannel(&card->dch);
+ write_lock_irqsave(&card_lock, flags);
+ list_del(&card->list);
+ write_unlock_irqrestore(&card_lock, flags);
+ kfree(card);
+ return err;
+}
+
+static int __devinit
+w6692_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int err = -ENOMEM;
+ struct w6692_hw *card;
+ struct w6692map *m = (struct w6692map *)ent->driver_data;
+
+ card = kzalloc(sizeof(struct w6692_hw), GFP_KERNEL);
+ if (!card) {
+ pr_info("No kmem for w6692 card\n");
+ return err;
+ }
+ card->pdev = pdev;
+ card->subtype = m->subtype;
+ err = pci_enable_device(pdev);
+ if (err) {
+ kfree(card);
+ return err;
+ }
+
+ printk(KERN_INFO "mISDN_w6692: found adapter %s at %s\n",
+ m->name, pci_name(pdev));
+
+ card->addr = pci_resource_start(pdev, 1);
+ card->irq = pdev->irq;
+ pci_set_drvdata(pdev, card);
+ err = setup_instance(card);
+ if (err)
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void __devexit
+w6692_remove_pci(struct pci_dev *pdev)
+{
+ struct w6692_hw *card = pci_get_drvdata(pdev);
+
+ if (card)
+ release_card(card);
+ else
+ if (debug)
+ pr_notice("%s: drvdata allready removed\n", __func__);
+}
+
+static struct pci_device_id w6692_ids[] = {
+ { PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[0]},
+ { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692,
+ PCI_VENDOR_ID_USR, PCI_DEVICE_ID_USR_6692, 0, 0,
+ (ulong)&w6692_map[2]},
+ { PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, (ulong)&w6692_map[1]},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, w6692_ids);
+
+static struct pci_driver w6692_driver = {
+ .name = "w6692",
+ .probe = w6692_probe,
+ .remove = __devexit_p(w6692_remove_pci),
+ .id_table = w6692_ids,
+};
+
+static int __init w6692_init(void)
+{
+ int err;
+
+ pr_notice("Winbond W6692 PCI driver Rev. %s\n", W6692_REV);
+
+ err = pci_register_driver(&w6692_driver);
+ return err;
+}
+
+static void __exit w6692_cleanup(void)
+{
+ pci_unregister_driver(&w6692_driver);
+}
+
+module_init(w6692_init);
+module_exit(w6692_cleanup);
diff --git a/drivers/isdn/hardware/mISDN/w6692.h b/drivers/isdn/hardware/mISDN/w6692.h
new file mode 100644
index 00000000000..f95697757fd
--- /dev/null
+++ b/drivers/isdn/hardware/mISDN/w6692.h
@@ -0,0 +1,190 @@
+/*
+ * Winbond W6692 specific defines
+ *
+ * Author Karsten Keil <keil@isdn4linux.de>
+ * based on the w6692 I4L driver from Petr Novak <petr.novak@i.cz>
+ *
+ * Copyright 2009 by Karsten Keil <keil@isdn4linux.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* Specifications of W6692 registers */
+
+#define W_D_RFIFO 0x00 /* R */
+#define W_D_XFIFO 0x04 /* W */
+#define W_D_CMDR 0x08 /* W */
+#define W_D_MODE 0x0c /* R/W */
+#define W_D_TIMR 0x10 /* R/W */
+#define W_ISTA 0x14 /* R_clr */
+#define W_IMASK 0x18 /* R/W */
+#define W_D_EXIR 0x1c /* R_clr */
+#define W_D_EXIM 0x20 /* R/W */
+#define W_D_STAR 0x24 /* R */
+#define W_D_RSTA 0x28 /* R */
+#define W_D_SAM 0x2c /* R/W */
+#define W_D_SAP1 0x30 /* R/W */
+#define W_D_SAP2 0x34 /* R/W */
+#define W_D_TAM 0x38 /* R/W */
+#define W_D_TEI1 0x3c /* R/W */
+#define W_D_TEI2 0x40 /* R/W */
+#define W_D_RBCH 0x44 /* R */
+#define W_D_RBCL 0x48 /* R */
+#define W_TIMR2 0x4c /* W */
+#define W_L1_RC 0x50 /* R/W */
+#define W_D_CTL 0x54 /* R/W */
+#define W_CIR 0x58 /* R */
+#define W_CIX 0x5c /* W */
+#define W_SQR 0x60 /* R */
+#define W_SQX 0x64 /* W */
+#define W_PCTL 0x68 /* R/W */
+#define W_MOR 0x6c /* R */
+#define W_MOX 0x70 /* R/W */
+#define W_MOSR 0x74 /* R_clr */
+#define W_MOCR 0x78 /* R/W */
+#define W_GCR 0x7c /* R/W */
+
+#define W_B_RFIFO 0x80 /* R */
+#define W_B_XFIFO 0x84 /* W */
+#define W_B_CMDR 0x88 /* W */
+#define W_B_MODE 0x8c /* R/W */
+#define W_B_EXIR 0x90 /* R_clr */
+#define W_B_EXIM 0x94 /* R/W */
+#define W_B_STAR 0x98 /* R */
+#define W_B_ADM1 0x9c /* R/W */
+#define W_B_ADM2 0xa0 /* R/W */
+#define W_B_ADR1 0xa4 /* R/W */
+#define W_B_ADR2 0xa8 /* R/W */
+#define W_B_RBCL 0xac /* R */
+#define W_B_RBCH 0xb0 /* R */
+
+#define W_XADDR 0xf4 /* R/W */
+#define W_XDATA 0xf8 /* R/W */
+#define W_EPCTL 0xfc /* W */
+
+/* W6692 register bits */
+
+#define W_D_CMDR_XRST 0x01
+#define W_D_CMDR_XME 0x02
+#define W_D_CMDR_XMS 0x08
+#define W_D_CMDR_STT 0x10
+#define W_D_CMDR_RRST 0x40
+#define W_D_CMDR_RACK 0x80
+
+#define W_D_MODE_RLP 0x01
+#define W_D_MODE_DLP 0x02
+#define W_D_MODE_MFD 0x04
+#define W_D_MODE_TEE 0x08
+#define W_D_MODE_TMS 0x10
+#define W_D_MODE_RACT 0x40
+#define W_D_MODE_MMS 0x80
+
+#define W_INT_B2_EXI 0x01
+#define W_INT_B1_EXI 0x02
+#define W_INT_D_EXI 0x04
+#define W_INT_XINT0 0x08
+#define W_INT_XINT1 0x10
+#define W_INT_D_XFR 0x20
+#define W_INT_D_RME 0x40
+#define W_INT_D_RMR 0x80
+
+#define W_D_EXI_WEXP 0x01
+#define W_D_EXI_TEXP 0x02
+#define W_D_EXI_ISC 0x04
+#define W_D_EXI_MOC 0x08
+#define W_D_EXI_TIN2 0x10
+#define W_D_EXI_XCOL 0x20
+#define W_D_EXI_XDUN 0x40
+#define W_D_EXI_RDOV 0x80
+
+#define W_D_STAR_DRDY 0x10
+#define W_D_STAR_XBZ 0x20
+#define W_D_STAR_XDOW 0x80
+
+#define W_D_RSTA_RMB 0x10
+#define W_D_RSTA_CRCE 0x20
+#define W_D_RSTA_RDOV 0x40
+
+#define W_D_CTL_SRST 0x20
+
+#define W_CIR_SCC 0x80
+#define W_CIR_ICC 0x40
+#define W_CIR_COD_MASK 0x0f
+
+#define W_PCTL_PCX 0x01
+#define W_PCTL_XMODE 0x02
+#define W_PCTL_OE0 0x04
+#define W_PCTL_OE1 0x08
+#define W_PCTL_OE2 0x10
+#define W_PCTL_OE3 0x20
+#define W_PCTL_OE4 0x40
+#define W_PCTL_OE5 0x80
+
+#define W_B_CMDR_XRST 0x01
+#define W_B_CMDR_XME 0x02
+#define W_B_CMDR_XMS 0x04
+#define W_B_CMDR_RACT 0x20
+#define W_B_CMDR_RRST 0x40
+#define W_B_CMDR_RACK 0x80
+
+#define W_B_MODE_FTS0 0x01
+#define W_B_MODE_FTS1 0x02
+#define W_B_MODE_SW56 0x04
+#define W_B_MODE_BSW0 0x08
+#define W_B_MODE_BSW1 0x10
+#define W_B_MODE_EPCM 0x20
+#define W_B_MODE_ITF 0x40
+#define W_B_MODE_MMS 0x80
+
+#define W_B_EXI_XDUN 0x01
+#define W_B_EXI_XFR 0x02
+#define W_B_EXI_RDOV 0x10
+#define W_B_EXI_RME 0x20
+#define W_B_EXI_RMR 0x40
+
+#define W_B_STAR_XBZ 0x01
+#define W_B_STAR_XDOW 0x04
+#define W_B_STAR_RMB 0x10
+#define W_B_STAR_CRCE 0x20
+#define W_B_STAR_RDOV 0x40
+
+#define W_B_RBCH_LOV 0x20
+
+/* W6692 Layer1 commands */
+
+#define W_L1CMD_ECK 0x00
+#define W_L1CMD_RST 0x01
+#define W_L1CMD_SCP 0x04
+#define W_L1CMD_SSP 0x02
+#define W_L1CMD_AR8 0x08
+#define W_L1CMD_AR10 0x09
+#define W_L1CMD_EAL 0x0a
+#define W_L1CMD_DRC 0x0f
+
+/* W6692 Layer1 indications */
+
+#define W_L1IND_CE 0x07
+#define W_L1IND_DRD 0x00
+#define W_L1IND_LD 0x04
+#define W_L1IND_ARD 0x08
+#define W_L1IND_TI 0x0a
+#define W_L1IND_ATI 0x0b
+#define W_L1IND_AI8 0x0c
+#define W_L1IND_AI10 0x0d
+#define W_L1IND_CD 0x0f
+
+/* FIFO thresholds */
+#define W_D_FIFO_THRESH 64
+#define W_B_FIFO_THRESH 64
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 7832d8ba8e4..3464ebc4cdb 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -391,6 +391,7 @@ comment "HiSax sub driver modules"
config HISAX_ST5481
tristate "ST5481 USB ISDN modem (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
+ select ISDN_HDLC
select CRC_CCITT
select BITREVERSE
help
@@ -418,11 +419,6 @@ config HISAX_FRITZ_PCIPNP
(the latter also needs you to select "ISA Plug and Play support"
from the menu "Plug and Play configuration")
-config HISAX_HDLC
- bool
- depends on HISAX_ST5481
- default y
-
config HISAX_AVM_A1_PCMCIA
bool
depends on HISAX_AVM_A1_CS
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index c7a3794bdae..ab638b083df 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -16,10 +16,6 @@ obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o
obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o
obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
-ifdef CONFIG_HISAX_HDLC
-obj-$(CONFIG_ISDN_DRV_HISAX) += isdnhdlc.o
-endif
-
# Multipart objects.
hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
index 341faf58a65..bf526a7a63a 100644
--- a/drivers/isdn/hisax/amd7930_fn.c
+++ b/drivers/isdn/hisax/amd7930_fn.c
@@ -238,8 +238,6 @@ Amd7930_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 025a20d487c..475b1a02000 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -833,8 +833,6 @@ static struct FsmNode fnlist[] __initdata =
};
/* *INDENT-ON* */
-#define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
-
int __init
CallcNew(void)
{
@@ -842,7 +840,7 @@ CallcNew(void)
callcfsm.event_count = EVENT_COUNT;
callcfsm.strEvent = strEvent;
callcfsm.strState = strState;
- return FsmNew(&callcfsm, fnlist, FNCOUNT);
+ return FsmNew(&callcfsm, fnlist, ARRAY_SIZE(fnlist));
}
void
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 3d337d924c2..d110a77940a 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -1506,8 +1506,6 @@ hfcpci_bh(struct work_struct *work)
u_long flags;
// struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
if (!cs->hw.hfcpci.nt_mode)
switch (cs->dc.hfcpci.ph_state) {
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index d92e8d6c2ae..419f87cad8c 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -1255,8 +1255,6 @@ hfcsx_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
u_long flags;
- if (!cs)
- return;
if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
if (!cs->hw.hfcsx.nt_mode)
switch (cs->dc.hfcsx.ph_state) {
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
index 682cac32f25..9aba646ba22 100644
--- a/drivers/isdn/hisax/icc.c
+++ b/drivers/isdn/hisax/icc.c
@@ -83,8 +83,6 @@ icc_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
index 07b1673122b..a19354d9434 100644
--- a/drivers/isdn/hisax/isac.c
+++ b/drivers/isdn/hisax/isac.c
@@ -86,8 +86,6 @@ isac_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
diff --git a/drivers/isdn/hisax/isdnhdlc.h b/drivers/isdn/hisax/isdnhdlc.h
deleted file mode 100644
index cf0a95a2401..00000000000
--- a/drivers/isdn/hisax/isdnhdlc.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * isdnhdlc.h -- General purpose ISDN HDLC decoder.
- *
- * Implementation of a HDLC decoder/encoder in software.
- * Neccessary because some ISDN devices don't have HDLC
- * controllers. Also included: a bit reversal table.
- *
- *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
- * 2001 Frode Isaksen <fisaksen@bewan.com>
- * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef __ISDNHDLC_H__
-#define __ISDNHDLC_H__
-
-struct isdnhdlc_vars {
- int bit_shift;
- int hdlc_bits1;
- int data_bits;
- int ffbit_shift; // encoding only
- int state;
- int dstpos;
-
- unsigned short crc;
-
- unsigned char cbin;
- unsigned char shift_reg;
- unsigned char ffvalue;
-
- unsigned int data_received:1; // set if transferring data
- unsigned int dchannel:1; // set if D channel (send idle instead of flags)
- unsigned int do_adapt56:1; // set if 56K adaptation
- unsigned int do_closing:1; // set if in closing phase (need to send CRC + flag
-};
-
-
-/*
- The return value from isdnhdlc_decode is
- the frame length, 0 if no complete frame was decoded,
- or a negative error number
-*/
-#define HDLC_FRAMING_ERROR 1
-#define HDLC_CRC_ERROR 2
-#define HDLC_LENGTH_ERROR 3
-
-extern void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56);
-
-extern int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
- unsigned char *dst, int dsize);
-
-extern void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc,int is_d_channel,int do_adapt56);
-
-extern int isdnhdlc_encode (struct isdnhdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
- unsigned char *dst,int dsize);
-
-#endif /* __ISDNHDLC_H__ */
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 317f16f516f..9ce6abe05b1 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -647,8 +647,6 @@ static struct FsmNode L1SFnList[] __initdata =
{ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
};
-#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode))
-
#ifdef HISAX_UINTERFACE
static void
l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
@@ -706,8 +704,6 @@ static struct FsmNode L1UFnList[] __initdata =
{ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact},
};
-#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode))
-
#endif
static void
@@ -754,8 +750,6 @@ static struct FsmNode L1BFnList[] __initdata =
{ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact},
};
-#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
-
int __init
Isdnl1New(void)
{
@@ -765,7 +759,7 @@ Isdnl1New(void)
l1fsm_s.event_count = L1_EVENT_COUNT;
l1fsm_s.strEvent = strL1Event;
l1fsm_s.strState = strL1SState;
- retval = FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
+ retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList));
if (retval)
return retval;
@@ -773,7 +767,7 @@ Isdnl1New(void)
l1fsm_b.event_count = L1_EVENT_COUNT;
l1fsm_b.strEvent = strL1Event;
l1fsm_b.strState = strL1BState;
- retval = FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
+ retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList));
if (retval) {
FsmFree(&l1fsm_s);
return retval;
@@ -783,7 +777,7 @@ Isdnl1New(void)
l1fsm_u.event_count = L1_EVENT_COUNT;
l1fsm_u.strEvent = strL1Event;
l1fsm_u.strState = strL1UState;
- retval = FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
+ retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList));
if (retval) {
FsmFree(&l1fsm_s);
FsmFree(&l1fsm_b);
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index 3446f249d67..7b9496a63b5 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -1623,8 +1623,6 @@ static struct FsmNode L2FnList[] __initdata =
{ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
};
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
static void
isdnl2_l1l2(struct PStack *st, int pr, void *arg)
{
@@ -1836,7 +1834,7 @@ Isdnl2New(void)
l2fsm.event_count = L2_EVENT_COUNT;
l2fsm.strEvent = strL2Event;
l2fsm.strState = strL2State;
- return FsmNew(&l2fsm, L2FnList, L2_FN_COUNT);
+ return FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList));
}
void
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index 935f23356fa..06766022d3a 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -543,8 +543,6 @@ static struct FsmNode L3FnList[] __initdata =
};
/* *INDENT-ON* */
-#define L3_FN_COUNT (sizeof(L3FnList)/sizeof(struct FsmNode))
-
void
l3_msg(struct PStack *st, int pr, void *arg)
{
@@ -587,7 +585,7 @@ Isdnl3New(void)
l3fsm.event_count = L3_EVENT_COUNT;
l3fsm.strEvent = strL3Event;
l3fsm.strState = strL3State;
- return FsmNew(&l3fsm, L3FnList, L3_FN_COUNT);
+ return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList));
}
void
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index c5c36eeff26..b0554f80bfb 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -698,9 +698,6 @@ static struct stateentry downstl[] =
CC_T308_2, l3_1tr6_t308_2},
};
-#define DOWNSTL_LEN \
- (sizeof(downstl) / sizeof(struct stateentry))
-
static struct stateentry datastln1[] =
{
{SBIT(0),
@@ -735,9 +732,6 @@ static struct stateentry datastln1[] =
MT_N1_REL_ACK, l3_1tr6_rel_ack}
};
-#define DATASTLN1_LEN \
- (sizeof(datastln1) / sizeof(struct stateentry))
-
static struct stateentry manstatelist[] =
{
{SBIT(2),
@@ -746,8 +740,6 @@ static struct stateentry manstatelist[] =
DL_RELEASE | INDICATION, l3_1tr6_dl_release},
};
-#define MANSLLEN \
- (sizeof(manstatelist) / sizeof(struct stateentry))
/* *INDENT-ON* */
static void
@@ -840,11 +832,11 @@ up1tr6(struct PStack *st, int pr, void *arg)
mt = MT_N1_INVALID;
}
}
- for (i = 0; i < DATASTLN1_LEN; i++)
+ for (i = 0; i < ARRAY_SIZE(datastln1); i++)
if ((mt == datastln1[i].primitive) &&
((1 << proc->state) & datastln1[i].state))
break;
- if (i == DATASTLN1_LEN) {
+ if (i == ARRAY_SIZE(datastln1)) {
dev_kfree_skb(skb);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
@@ -892,11 +884,11 @@ down1tr6(struct PStack *st, int pr, void *arg)
proc = arg;
}
- for (i = 0; i < DOWNSTL_LEN; i++)
+ for (i = 0; i < ARRAY_SIZE(downstl); i++)
if ((pr == downstl[i].primitive) &&
((1 << proc->state) & downstl[i].state))
break;
- if (i == DOWNSTL_LEN) {
+ if (i == ARRAY_SIZE(downstl)) {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp, "down1tr6 state %d prim %d unhandled",
proc->state, pr);
@@ -922,11 +914,11 @@ man1tr6(struct PStack *st, int pr, void *arg)
printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr);
return;
}
- for (i = 0; i < MANSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
if ((pr == manstatelist[i].primitive) &&
((1 << proc->state) & manstatelist[i].state))
break;
- if (i == MANSLLEN) {
+ if (i == ARRAY_SIZE(manstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled",
proc->callref & 0x7f, proc->state, pr);
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 99feae8b921..a12fa4d3490 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -2820,9 +2820,6 @@ static struct stateentry downstatelist[] =
CC_T309, l3dss1_dl_release},
};
-#define DOWNSLLEN \
- (sizeof(downstatelist) / sizeof(struct stateentry))
-
static struct stateentry datastatelist[] =
{
{ALL_STATES,
@@ -2875,9 +2872,6 @@ static struct stateentry datastatelist[] =
MT_RESUME_REJECT, l3dss1_resume_rej},
};
-#define DATASLLEN \
- (sizeof(datastatelist) / sizeof(struct stateentry))
-
static struct stateentry globalmes_list[] =
{
{ALL_STATES,
@@ -2888,8 +2882,6 @@ static struct stateentry globalmes_list[] =
MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack},
*/
};
-#define GLOBALM_LEN \
- (sizeof(globalmes_list) / sizeof(struct stateentry))
static struct stateentry manstatelist[] =
{
@@ -2903,8 +2895,6 @@ static struct stateentry manstatelist[] =
DL_RELEASE | INDICATION, l3dss1_dl_release},
};
-#define MANSLLEN \
- (sizeof(manstatelist) / sizeof(struct stateentry))
/* *INDENT-ON* */
@@ -2918,11 +2908,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb)
struct l3_process *proc = st->l3.global;
proc->callref = skb->data[2]; /* cr flag */
- for (i = 0; i < GLOBALM_LEN; i++)
+ for (i = 0; i < ARRAY_SIZE(globalmes_list); i++)
if ((mt == globalmes_list[i].primitive) &&
((1 << proc->state) & globalmes_list[i].state))
break;
- if (i == GLOBALM_LEN) {
+ if (i == ARRAY_SIZE(globalmes_list)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "dss1 global state %d mt %x unhandled",
proc->state, mt);
@@ -3097,11 +3087,11 @@ dss1up(struct PStack *st, int pr, void *arg)
}
if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
l3dss1_deliver_display(proc, pr, p); /* Display IE included */
- for (i = 0; i < DATASLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(datastatelist); i++)
if ((mt == datastatelist[i].primitive) &&
((1 << proc->state) & datastatelist[i].state))
break;
- if (i == DATASLLEN) {
+ if (i == ARRAY_SIZE(datastatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "dss1up%sstate %d mt %#x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
@@ -3156,11 +3146,11 @@ dss1down(struct PStack *st, int pr, void *arg)
return;
}
- for (i = 0; i < DOWNSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(downstatelist); i++)
if ((pr == downstatelist[i].primitive) &&
((1 << proc->state) & downstatelist[i].state))
break;
- if (i == DOWNSLLEN) {
+ if (i == ARRAY_SIZE(downstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "dss1down state %d prim %#x unhandled",
proc->state, pr);
@@ -3184,11 +3174,11 @@ dss1man(struct PStack *st, int pr, void *arg)
printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr);
return;
}
- for (i = 0; i < MANSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
if ((pr == manstatelist[i].primitive) &&
((1 << proc->state) & manstatelist[i].state))
break;
- if (i == MANSLLEN) {
+ if (i == ARRAY_SIZE(manstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "cr %d dss1man state %d prim %#x unhandled",
proc->callref & 0x7f, proc->state, pr);
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
index f7041d5ba64..4622d43c7e1 100644
--- a/drivers/isdn/hisax/l3ni1.c
+++ b/drivers/isdn/hisax/l3ni1.c
@@ -2755,9 +2755,6 @@ static struct stateentry downstatelist[] =
CC_TSPID, l3ni1_spid_tout },
};
-#define DOWNSLLEN \
- (sizeof(downstatelist) / sizeof(struct stateentry))
-
static struct stateentry datastatelist[] =
{
{ALL_STATES,
@@ -2810,9 +2807,6 @@ static struct stateentry datastatelist[] =
MT_RESUME_REJECT, l3ni1_resume_rej},
};
-#define DATASLLEN \
- (sizeof(datastatelist) / sizeof(struct stateentry))
-
static struct stateentry globalmes_list[] =
{
{ALL_STATES,
@@ -2825,8 +2819,6 @@ static struct stateentry globalmes_list[] =
{ SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send },
{ SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid },
};
-#define GLOBALM_LEN \
- (sizeof(globalmes_list) / sizeof(struct stateentry))
static struct stateentry manstatelist[] =
{
@@ -2840,8 +2832,6 @@ static struct stateentry manstatelist[] =
DL_RELEASE | INDICATION, l3ni1_dl_release},
};
-#define MANSLLEN \
- (sizeof(manstatelist) / sizeof(struct stateentry))
/* *INDENT-ON* */
@@ -2858,11 +2848,11 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb)
proc->callref = skb->data[2]; /* cr flag */
else
proc->callref = 0;
- for (i = 0; i < GLOBALM_LEN; i++)
+ for (i = 0; i < ARRAY_SIZE(globalmes_list); i++)
if ((mt == globalmes_list[i].primitive) &&
((1 << proc->state) & globalmes_list[i].state))
break;
- if (i == GLOBALM_LEN) {
+ if (i == ARRAY_SIZE(globalmes_list)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "ni1 global state %d mt %x unhandled",
proc->state, mt);
@@ -3049,11 +3039,11 @@ ni1up(struct PStack *st, int pr, void *arg)
}
if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
l3ni1_deliver_display(proc, pr, p); /* Display IE included */
- for (i = 0; i < DATASLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(datastatelist); i++)
if ((mt == datastatelist[i].primitive) &&
((1 << proc->state) & datastatelist[i].state))
break;
- if (i == DATASLLEN) {
+ if (i == ARRAY_SIZE(datastatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "ni1up%sstate %d mt %#x unhandled",
(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
@@ -3108,11 +3098,11 @@ ni1down(struct PStack *st, int pr, void *arg)
return;
}
- for (i = 0; i < DOWNSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(downstatelist); i++)
if ((pr == downstatelist[i].primitive) &&
((1 << proc->state) & downstatelist[i].state))
break;
- if (i == DOWNSLLEN) {
+ if (i == ARRAY_SIZE(downstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "ni1down state %d prim %#x unhandled",
proc->state, pr);
@@ -3136,11 +3126,11 @@ ni1man(struct PStack *st, int pr, void *arg)
printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr);
return;
}
- for (i = 0; i < MANSLLEN; i++)
+ for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
if ((pr == manstatelist[i].primitive) &&
((1 << proc->state) & manstatelist[i].state))
break;
- if (i == MANSLLEN) {
+ if (i == ARRAY_SIZE(manstatelist)) {
if (st->l3.debug & L3_DEB_STATE) {
l3_debug(st, "cr %d ni1man state %d prim %#x unhandled",
proc->callref & 0x7f, proc->state, pr);
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index aacbf0d14b6..8b853d58e82 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -140,7 +140,7 @@ struct MessageType {
}
};
-#define MTSIZE sizeof(mtlist)/sizeof(struct MessageType)
+#define MTSIZE ARRAY_SIZE(mtlist)
static
struct MessageType mt_n0[] =
@@ -157,7 +157,7 @@ struct MessageType mt_n0[] =
{MT_N0_CLO_ACK, "CLOse ACKnowledge"}
};
-#define MT_N0_LEN (sizeof(mt_n0) / sizeof(struct MessageType))
+#define MT_N0_LEN ARRAY_SIZE(mt_n0)
static
struct MessageType mt_n1[] =
@@ -194,7 +194,7 @@ struct MessageType mt_n1[] =
{MT_N1_STAT, "STATus"}
};
-#define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
+#define MT_N1_LEN ARRAY_SIZE(mt_n1)
static int
@@ -438,7 +438,7 @@ struct CauseValue {
},
};
-#define CVSIZE sizeof(cvlist)/sizeof(struct CauseValue)
+#define CVSIZE ARRAY_SIZE(cvlist)
static
int
@@ -516,7 +516,7 @@ struct MessageType cause_1tr6[] =
{CAUSE_UserInfoDiscarded, "User Info Discarded"}
};
-static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
+static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6);
static int
prcause_1tr6(char *dest, u_char * p)
@@ -865,7 +865,7 @@ struct DTag { /* Display tags */
{ 0x96, "Redirection name" },
{ 0x9e, "Text" },
};
-#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag)
+#define DTAGSIZE ARRAY_SIZE(dtaglist)
static int
disptext_ni1(char *dest, u_char * p)
@@ -1074,7 +1074,7 @@ struct InformationElement {
};
-#define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
+#define IESIZE ARRAY_SIZE(ielist)
static
struct InformationElement ielist_ni1[] = {
@@ -1102,7 +1102,7 @@ struct InformationElement ielist_ni1[] = {
};
-#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement)
+#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1)
static
struct InformationElement ielist_ni1_cs5[] = {
@@ -1110,14 +1110,14 @@ struct InformationElement ielist_ni1_cs5[] = {
{ 0x2a, "Display text", disptext_ni1 },
};
-#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement)
+#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5)
static
struct InformationElement ielist_ni1_cs6[] = {
{ 0x7b, "Call appearance", general_ni1 },
};
-#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement)
+#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6)
static struct InformationElement we_0[] =
{
@@ -1133,7 +1133,7 @@ static struct InformationElement we_0[] =
{WE0_userInfo, "User Info", general}
};
-#define WE_0_LEN (sizeof(we_0) / sizeof(struct InformationElement))
+#define WE_0_LEN ARRAY_SIZE(we_0)
static struct InformationElement we_6[] =
{
@@ -1145,7 +1145,7 @@ static struct InformationElement we_6[] =
{WE6_statusCalled, "Status Called", general},
{WE6_addTransAttr, "Additional Transmission Attributes", general}
};
-#define WE_6_LEN (sizeof(we_6) / sizeof(struct InformationElement))
+#define WE_6_LEN ARRAY_SIZE(we_6)
int
QuickHex(char *txt, u_char * p, int cnt)
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
index cff7a635433..64f78a8c28c 100644
--- a/drivers/isdn/hisax/st5481.h
+++ b/drivers/isdn/hisax/st5481.h
@@ -226,7 +226,7 @@ printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
#define INFO(format, arg...) \
printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg)
-#include "isdnhdlc.h"
+#include <linux/isdn/hdlc.h>
#include "fsm.h"
#include "hisax_if.h"
#include <linux/skbuff.h>
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
index 0074b600a0e..95b1cdd9795 100644
--- a/drivers/isdn/hisax/st5481_b.c
+++ b/drivers/isdn/hisax/st5481_b.c
@@ -218,7 +218,10 @@ static void st5481B_mode(struct st5481_bcs *bcs, int mode)
if (bcs->mode != L1_MODE_NULL) {
// Open the B channel
if (bcs->mode != L1_MODE_TRANS) {
- isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
+ u32 features = HDLC_BITREVERSE;
+ if (bcs->mode == L1_MODE_HDLC_56K)
+ features |= HDLC_56KBIT;
+ isdnhdlc_out_init(&b_out->hdlc_state, features);
}
st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL);
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
index 077991c1cd0..39e8e49cfd2 100644
--- a/drivers/isdn/hisax/st5481_d.c
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -417,7 +417,7 @@ static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg)
DBG(2,"len=%d",skb->len);
- isdnhdlc_out_init(&d_out->hdlc_state, 1, 0);
+ isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE);
if (test_and_set_bit(buf_nr, &d_out->busy)) {
WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
index 2b3a055059e..10d41c5d73e 100644
--- a/drivers/isdn/hisax/st5481_usb.c
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -637,10 +637,13 @@ void st5481_in_mode(struct st5481_in *in, int mode)
usb_unlink_urb(in->urb[1]);
if (in->mode != L1_MODE_NULL) {
- if (in->mode != L1_MODE_TRANS)
- isdnhdlc_rcv_init(&in->hdlc_state,
- in->mode == L1_MODE_HDLC_56K);
-
+ if (in->mode != L1_MODE_TRANS) {
+ u32 features = HDLC_BITREVERSE;
+
+ if (in->mode == L1_MODE_HDLC_56K)
+ features |= HDLC_56KBIT;
+ isdnhdlc_rcv_init(&in->hdlc_state, features);
+ }
st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
st5481_usb_device_ctrl_msg(in->adapter, in->counter,
in->packet_size,
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
index ceb0df92fd3..6e65424f1f0 100644
--- a/drivers/isdn/hisax/tei.c
+++ b/drivers/isdn/hisax/tei.c
@@ -447,8 +447,6 @@ static struct FsmNode TeiFnList[] __initdata =
{ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req},
};
-#define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
-
int __init
TeiNew(void)
{
@@ -456,7 +454,7 @@ TeiNew(void)
teifsm.event_count = TEI_EVENT_COUNT;
teifsm.strEvent = strTeiEvent;
teifsm.strState = strTeiState;
- return FsmNew(&teifsm, TeiFnList, TEI_FN_COUNT);
+ return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList));
}
void
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index bb1c8dd1a23..c4d862c11a6 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -105,8 +105,6 @@ W6692_bh(struct work_struct *work)
container_of(work, struct IsdnCardState, tqueue);
struct PStack *stptr;
- if (!cs)
- return;
if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
if (cs->debug)
debugl1(cs, "D-Channel Busy cleared");
diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c
index 579974cf4c9..c73004b3b2a 100644
--- a/drivers/isdn/hysdn/hysdn_net.c
+++ b/drivers/isdn/hysdn/hysdn_net.c
@@ -148,7 +148,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
if (lp->sk_count <= 3) {
schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue);
}
- return (0); /* success */
+ return NETDEV_TX_OK; /* success */
} /* net_send_packet */
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index ed3510f273d..dd744ffd240 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -2,6 +2,8 @@
# Old ISDN4Linux config
#
+if ISDN_I4L
+
config ISDN_PPP
bool "Support synchronous PPP"
depends on INET
@@ -135,3 +137,12 @@ source "drivers/isdn/act2000/Kconfig"
source "drivers/isdn/hysdn/Kconfig"
endmenu
+# end ISDN_I4L
+endif
+
+config ISDN_HDLC
+ tristate
+ depends on HISAX_ST5481
+ select CRC_CCITT
+ select BITREVERSE
+
diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile
index 49a06c0005d..cb9d3bb9fae 100644
--- a/drivers/isdn/i4l/Makefile
+++ b/drivers/isdn/i4l/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_ISDN_I4L) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
+obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o
# Multipart objects.
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index de4aad076eb..57bf4bf5027 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1051,12 +1051,12 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb)
isdn_net_dev *nd;
isdn_net_local *slp;
isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev);
- int retv = 0;
+ int retv = NETDEV_TX_OK;
if (((isdn_net_local *) netdev_priv(ndev))->master) {
printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* For the other encaps the header has already been built */
@@ -1202,7 +1202,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (lp->phone[1]) {
ulong flags;
@@ -1215,7 +1215,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
if(time_before(jiffies, lp->dialwait_timer)) {
isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
lp->dialwait_timer = 0;
}
@@ -1243,7 +1243,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_unreachable(ndev, skb,
"No channel");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* Log packet, which triggered dialing */
if (dev->net_verbose)
@@ -1258,7 +1258,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
dev_kfree_skb(skb);
isdn_net_unbind_channel(lp);
spin_unlock_irqrestore(&dev->lock, flags);
- return 0; /* STN (skb to nirvana) ;) */
+ return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */
}
#ifdef CONFIG_IPPP_FILTER
if (isdn_ppp_autodial_filter(skb, lp)) {
@@ -1267,7 +1267,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&dev->lock, flags);
isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#endif
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1285,7 +1285,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
isdn_net_unreachable(ndev, skb,
"No phone number");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
} else {
/* Device is connected to an ISDN channel */
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index aa30b5cb351..2d14b64202a 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
isdn_net_dev *nd;
unsigned int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt,*ipts;
- int slot, retval = 0;
+ int slot, retval = NETDEV_TX_OK;
mlp = (isdn_net_local *) netdev_priv(netdev);
nd = mlp->netdev; /* get master lp */
@@ -1240,7 +1240,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
if (ipts->debug & 0x1)
printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
- retval = 1;
+ retval = NETDEV_TX_BUSY;
goto out;
}
@@ -1261,7 +1261,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
lp = isdn_net_get_locked_lp(nd);
if (!lp) {
printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
- retval = 1;
+ retval = NETDEV_TX_BUSY;
goto out;
}
/* we have our lp locked from now on */
diff --git a/drivers/isdn/hisax/isdnhdlc.c b/drivers/isdn/i4l/isdnhdlc.c
index c69a77a8006..c989aa35dc2 100644
--- a/drivers/isdn/hisax/isdnhdlc.c
+++ b/drivers/isdn/i4l/isdnhdlc.c
@@ -1,29 +1,32 @@
/*
* isdnhdlc.c -- General purpose ISDN HDLC decoder.
*
- *Copyright (C) 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
- * 2001 Frode Isaksen <fisaksen@bewan.com>
- * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
+ * Copyright (C)
+ * 2009 Karsten Keil <keil@b1-systems.de>
+ * 2002 Wolfgang Mües <wolfgang@iksw-muees.de>
+ * 2001 Frode Isaksen <fisaksen@bewan.com>
+ * 2001 Kai Germaschewski <kai.germaschewski@gmx.de>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/crc-ccitt.h>
-#include "isdnhdlc.h"
+#include <linux/isdn/hdlc.h>
+#include <linux/bitrev.h>
/*-------------------------------------------------------------------*/
@@ -36,44 +39,32 @@ MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------*/
enum {
- HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
- HDLC_GET_DATA,HDLC_FAST_FLAG
+ HDLC_FAST_IDLE, HDLC_GET_FLAG_B0, HDLC_GETFLAG_B1A6, HDLC_GETFLAG_B7,
+ HDLC_GET_DATA, HDLC_FAST_FLAG
};
enum {
- HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
- HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
- HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
- HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
+ HDLC_SEND_DATA, HDLC_SEND_CRC1, HDLC_SEND_FAST_FLAG,
+ HDLC_SEND_FIRST_FLAG, HDLC_SEND_CRC2, HDLC_SEND_CLOSING_FLAG,
+ HDLC_SEND_IDLE1, HDLC_SEND_FAST_IDLE, HDLC_SENDFLAG_B0,
+ HDLC_SENDFLAG_B1A6, HDLC_SENDFLAG_B7, STOPPED, HDLC_SENDFLAG_ONE
};
-void isdnhdlc_rcv_init (struct isdnhdlc_vars *hdlc, int do_adapt56)
+void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features)
{
- hdlc->bit_shift = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->ffbit_shift = 0;
- hdlc->data_received = 0;
+ memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
hdlc->state = HDLC_GET_DATA;
- hdlc->do_adapt56 = do_adapt56;
- hdlc->dchannel = 0;
- hdlc->crc = 0;
- hdlc->cbin = 0;
- hdlc->shift_reg = 0;
- hdlc->ffvalue = 0;
- hdlc->dstpos = 0;
+ if (features & HDLC_56KBIT)
+ hdlc->do_adapt56 = 1;
+ if (features & HDLC_BITREVERSE)
+ hdlc->do_bitreverse = 1;
}
+EXPORT_SYMBOL(isdnhdlc_out_init);
-void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_adapt56)
+void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features)
{
- hdlc->bit_shift = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->ffbit_shift = 0;
- hdlc->data_received = 0;
- hdlc->do_closing = 0;
- hdlc->ffvalue = 0;
- if (is_d_channel) {
+ memset(hdlc, 0, sizeof(struct isdnhdlc_vars));
+ if (features & HDLC_DCHANNEL) {
hdlc->dchannel = 1;
hdlc->state = HDLC_SEND_FIRST_FLAG;
} else {
@@ -82,16 +73,32 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada
hdlc->ffvalue = 0x7e;
}
hdlc->cbin = 0x7e;
- hdlc->bit_shift = 0;
- if(do_adapt56){
+ if (features & HDLC_56KBIT) {
hdlc->do_adapt56 = 1;
- hdlc->data_bits = 0;
hdlc->state = HDLC_SENDFLAG_B0;
- } else {
- hdlc->do_adapt56 = 0;
+ } else
hdlc->data_bits = 8;
+ if (features & HDLC_BITREVERSE)
+ hdlc->do_bitreverse = 1;
+}
+EXPORT_SYMBOL(isdnhdlc_rcv_init);
+
+static int
+check_frame(struct isdnhdlc_vars *hdlc)
+{
+ int status;
+
+ if (hdlc->dstpos < 2) /* too small - framing error */
+ status = -HDLC_FRAMING_ERROR;
+ else if (hdlc->crc != 0xf0b8) /* crc error */
+ status = -HDLC_CRC_ERROR;
+ else {
+ /* remove CRC */
+ hdlc->dstpos -= 2;
+ /* good frame */
+ status = hdlc->dstpos;
}
- hdlc->shift_reg = 0;
+ return status;
}
/*
@@ -121,40 +128,67 @@ void isdnhdlc_out_init (struct isdnhdlc_vars *hdlc, int is_d_channel, int do_ada
returns - number of decoded bytes in the destination buffer and status
flag.
*/
-int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
- int slen, int *count, unsigned char *dst, int dsize)
+int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, int slen,
+ int *count, u8 *dst, int dsize)
{
- int status=0;
+ int status = 0;
- static const unsigned char fast_flag[]={
- 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
+ static const unsigned char fast_flag[] = {
+ 0x00, 0x00, 0x00, 0x20, 0x30, 0x38, 0x3c, 0x3e, 0x3f
};
- static const unsigned char fast_flag_value[]={
- 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
+ static const unsigned char fast_flag_value[] = {
+ 0x00, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf, 0x9f, 0x3f
};
- static const unsigned char fast_abort[]={
- 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
+ static const unsigned char fast_abort[] = {
+ 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff
};
+#define handle_fast_flag(h) \
+ do {\
+ if (h->cbin == fast_flag[h->bit_shift]) {\
+ h->ffvalue = fast_flag_value[h->bit_shift];\
+ h->state = HDLC_FAST_FLAG;\
+ h->ffbit_shift = h->bit_shift;\
+ h->bit_shift = 1;\
+ } else {\
+ h->state = HDLC_GET_DATA;\
+ h->data_received = 0;\
+ } \
+ } while (0)
+
+#define handle_abort(h) \
+ do {\
+ h->shift_reg = fast_abort[h->ffbit_shift - 1];\
+ h->hdlc_bits1 = h->ffbit_shift - 2;\
+ if (h->hdlc_bits1 < 0)\
+ h->hdlc_bits1 = 0;\
+ h->data_bits = h->ffbit_shift - 1;\
+ h->state = HDLC_GET_DATA;\
+ h->data_received = 0;\
+ } while (0)
+
*count = slen;
- while(slen > 0){
- if(hdlc->bit_shift==0){
- hdlc->cbin = *src++;
+ while (slen > 0) {
+ if (hdlc->bit_shift == 0) {
+ /* the code is for bitreverse streams */
+ if (hdlc->do_bitreverse == 0)
+ hdlc->cbin = bitrev8(*src++);
+ else
+ hdlc->cbin = *src++;
slen--;
hdlc->bit_shift = 8;
- if(hdlc->do_adapt56){
- hdlc->bit_shift --;
- }
+ if (hdlc->do_adapt56)
+ hdlc->bit_shift--;
}
- switch(hdlc->state){
+ switch (hdlc->state) {
case STOPPED:
return 0;
case HDLC_FAST_IDLE:
- if(hdlc->cbin == 0xff){
+ if (hdlc->cbin == 0xff) {
hdlc->bit_shift = 0;
break;
}
@@ -163,32 +197,30 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->bit_shift = 8;
break;
case HDLC_GET_FLAG_B0:
- if(!(hdlc->cbin & 0x80)) {
+ if (!(hdlc->cbin & 0x80)) {
hdlc->state = HDLC_GETFLAG_B1A6;
hdlc->hdlc_bits1 = 0;
} else {
- if(!hdlc->do_adapt56){
- if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
+ if ((!hdlc->do_adapt56) &&
+ (++hdlc->hdlc_bits1 >= 8) &&
+ (hdlc->bit_shift == 1))
hdlc->state = HDLC_FAST_IDLE;
- }
}
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
+ hdlc->cbin <<= 1;
+ hdlc->bit_shift--;
break;
case HDLC_GETFLAG_B1A6:
- if(hdlc->cbin & 0x80){
+ if (hdlc->cbin & 0x80) {
hdlc->hdlc_bits1++;
- if(hdlc->hdlc_bits1==6){
+ if (hdlc->hdlc_bits1 == 6)
hdlc->state = HDLC_GETFLAG_B7;
- }
- } else {
+ } else
hdlc->hdlc_bits1 = 0;
- }
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
+ hdlc->cbin <<= 1;
+ hdlc->bit_shift--;
break;
case HDLC_GETFLAG_B7:
- if(hdlc->cbin & 0x80) {
+ if (hdlc->cbin & 0x80) {
hdlc->state = HDLC_GET_FLAG_B0;
} else {
hdlc->state = HDLC_GET_DATA;
@@ -198,74 +230,55 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->data_bits = 0;
hdlc->data_received = 0;
}
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
+ hdlc->cbin <<= 1;
+ hdlc->bit_shift--;
break;
case HDLC_GET_DATA:
- if(hdlc->cbin & 0x80){
+ if (hdlc->cbin & 0x80) {
hdlc->hdlc_bits1++;
- switch(hdlc->hdlc_bits1){
+ switch (hdlc->hdlc_bits1) {
case 6:
break;
case 7:
- if(hdlc->data_received) {
- // bad frame
+ if (hdlc->data_received)
+ /* bad frame */
status = -HDLC_FRAMING_ERROR;
- }
- if(!hdlc->do_adapt56){
- if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
- hdlc->state = HDLC_FAST_IDLE;
- hdlc->bit_shift=1;
+ if (!hdlc->do_adapt56) {
+ if (hdlc->cbin == fast_abort
+ [hdlc->bit_shift + 1]) {
+ hdlc->state =
+ HDLC_FAST_IDLE;
+ hdlc->bit_shift = 1;
break;
}
- } else {
+ } else
hdlc->state = HDLC_GET_FLAG_B0;
- }
break;
default:
- hdlc->shift_reg>>=1;
+ hdlc->shift_reg >>= 1;
hdlc->shift_reg |= 0x80;
hdlc->data_bits++;
break;
}
} else {
- switch(hdlc->hdlc_bits1){
+ switch (hdlc->hdlc_bits1) {
case 5:
break;
case 6:
- if(hdlc->data_received){
- if (hdlc->dstpos < 2) {
- status = -HDLC_FRAMING_ERROR;
- } else if (hdlc->crc != 0xf0b8){
- // crc error
- status = -HDLC_CRC_ERROR;
- } else {
- // remove CRC
- hdlc->dstpos -= 2;
- // good frame
- status = hdlc->dstpos;
- }
- }
+ if (hdlc->data_received)
+ status = check_frame(hdlc);
hdlc->crc = 0xffff;
hdlc->shift_reg = 0;
hdlc->data_bits = 0;
- if(!hdlc->do_adapt56){
- if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
- hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
- hdlc->state = HDLC_FAST_FLAG;
- hdlc->ffbit_shift = hdlc->bit_shift;
- hdlc->bit_shift = 1;
- } else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
- } else {
+ if (!hdlc->do_adapt56)
+ handle_fast_flag(hdlc);
+ else {
hdlc->state = HDLC_GET_DATA;
hdlc->data_received = 0;
}
break;
default:
- hdlc->shift_reg>>=1;
+ hdlc->shift_reg >>= 1;
hdlc->data_bits++;
break;
}
@@ -278,16 +291,17 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->bit_shift--;
return status;
}
- if(hdlc->data_bits==8){
+ if (hdlc->data_bits == 8) {
hdlc->data_bits = 0;
hdlc->data_received = 1;
- hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
+ hdlc->crc = crc_ccitt_byte(hdlc->crc,
+ hdlc->shift_reg);
- // good byte received
- if (hdlc->dstpos < dsize) {
+ /* good byte received */
+ if (hdlc->dstpos < dsize)
dst[hdlc->dstpos++] = hdlc->shift_reg;
- } else {
- // frame too long
+ else {
+ /* frame too long */
status = -HDLC_LENGTH_ERROR;
hdlc->dstpos = 0;
}
@@ -296,24 +310,18 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->bit_shift--;
break;
case HDLC_FAST_FLAG:
- if(hdlc->cbin==hdlc->ffvalue){
+ if (hdlc->cbin == hdlc->ffvalue) {
hdlc->bit_shift = 0;
break;
} else {
- if(hdlc->cbin == 0xff){
+ if (hdlc->cbin == 0xff) {
hdlc->state = HDLC_FAST_IDLE;
- hdlc->bit_shift=0;
- } else if(hdlc->ffbit_shift==8){
+ hdlc->bit_shift = 0;
+ } else if (hdlc->ffbit_shift == 8) {
hdlc->state = HDLC_GETFLAG_B7;
break;
- } else {
- hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
- hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
- if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = hdlc->ffbit_shift-1;
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
+ } else
+ handle_abort(hdlc);
}
break;
default:
@@ -323,7 +331,7 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
*count -= slen;
return 0;
}
-
+EXPORT_SYMBOL(isdnhdlc_decode);
/*
isdnhdlc_encode - encodes HDLC frames to a transparent bit stream.
@@ -343,59 +351,70 @@ int isdnhdlc_decode (struct isdnhdlc_vars *hdlc, const unsigned char *src,
dsize - destination buffer size
returns - number of encoded bytes in the destination buffer
*/
-int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
- unsigned short slen, int *count,
- unsigned char *dst, int dsize)
+int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, u16 slen,
+ int *count, u8 *dst, int dsize)
{
static const unsigned char xfast_flag_value[] = {
- 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
+ 0x7e, 0x3f, 0x9f, 0xcf, 0xe7, 0xf3, 0xf9, 0xfc, 0x7e
};
int len = 0;
*count = slen;
+ /* special handling for one byte frames */
+ if ((slen == 1) && (hdlc->state == HDLC_SEND_FAST_FLAG))
+ hdlc->state = HDLC_SENDFLAG_ONE;
while (dsize > 0) {
- if(hdlc->bit_shift==0){
- if(slen && !hdlc->do_closing){
+ if (hdlc->bit_shift == 0) {
+ if (slen && !hdlc->do_closing) {
hdlc->shift_reg = *src++;
slen--;
if (slen == 0)
- hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
+ /* closing sequence, CRC + flag(s) */
+ hdlc->do_closing = 1;
hdlc->bit_shift = 8;
} else {
- if(hdlc->state == HDLC_SEND_DATA){
- if(hdlc->data_received){
+ if (hdlc->state == HDLC_SEND_DATA) {
+ if (hdlc->data_received) {
hdlc->state = HDLC_SEND_CRC1;
hdlc->crc ^= 0xffff;
hdlc->bit_shift = 8;
- hdlc->shift_reg = hdlc->crc & 0xff;
- } else if(!hdlc->do_adapt56){
- hdlc->state = HDLC_SEND_FAST_FLAG;
- } else {
- hdlc->state = HDLC_SENDFLAG_B0;
- }
+ hdlc->shift_reg =
+ hdlc->crc & 0xff;
+ } else if (!hdlc->do_adapt56)
+ hdlc->state =
+ HDLC_SEND_FAST_FLAG;
+ else
+ hdlc->state =
+ HDLC_SENDFLAG_B0;
}
}
}
- switch(hdlc->state){
+ switch (hdlc->state) {
case STOPPED:
while (dsize--)
*dst++ = 0xff;
-
return dsize;
case HDLC_SEND_FAST_FLAG:
hdlc->do_closing = 0;
- if(slen == 0){
- *dst++ = hdlc->ffvalue;
+ if (slen == 0) {
+ /* the code is for bitreverse streams */
+ if (hdlc->do_bitreverse == 0)
+ *dst++ = bitrev8(hdlc->ffvalue);
+ else
+ *dst++ = hdlc->ffvalue;
len++;
dsize--;
break;
}
- if(hdlc->bit_shift==8){
- hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
+ /* fall through */
+ case HDLC_SENDFLAG_ONE:
+ if (hdlc->bit_shift == 8) {
+ hdlc->cbin = hdlc->ffvalue >>
+ (8 - hdlc->data_bits);
hdlc->state = HDLC_SEND_DATA;
hdlc->crc = 0xffff;
hdlc->hdlc_bits1 = 0;
@@ -413,17 +432,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->cbin <<= 1;
hdlc->data_bits++;
hdlc->cbin++;
- if(++hdlc->hdlc_bits1 == 6)
+ if (++hdlc->hdlc_bits1 == 6)
hdlc->state = HDLC_SENDFLAG_B7;
break;
case HDLC_SENDFLAG_B7:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(slen == 0){
+ if (slen == 0) {
hdlc->state = HDLC_SENDFLAG_B0;
break;
}
- if(hdlc->bit_shift==8){
+ if (hdlc->bit_shift == 8) {
hdlc->state = HDLC_SEND_DATA;
hdlc->crc = 0xffff;
hdlc->hdlc_bits1 = 0;
@@ -432,7 +451,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
break;
case HDLC_SEND_FIRST_FLAG:
hdlc->data_received = 1;
- if(hdlc->data_bits==8){
+ if (hdlc->data_bits == 8) {
hdlc->state = HDLC_SEND_DATA;
hdlc->crc = 0xffff;
hdlc->hdlc_bits1 = 0;
@@ -440,11 +459,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
}
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->shift_reg & 0x01)
+ if (hdlc->shift_reg & 0x01)
hdlc->cbin++;
hdlc->shift_reg >>= 1;
hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
+ if (hdlc->bit_shift == 0) {
hdlc->state = HDLC_SEND_DATA;
hdlc->crc = 0xffff;
hdlc->hdlc_bits1 = 0;
@@ -453,14 +472,14 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
case HDLC_SEND_DATA:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
+ if (hdlc->hdlc_bits1 == 5) {
hdlc->hdlc_bits1 = 0;
break;
}
- if(hdlc->bit_shift==8){
- hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
- }
- if(hdlc->shift_reg & 0x01){
+ if (hdlc->bit_shift == 8)
+ hdlc->crc = crc_ccitt_byte(hdlc->crc,
+ hdlc->shift_reg);
+ if (hdlc->shift_reg & 0x01) {
hdlc->hdlc_bits1++;
hdlc->cbin++;
hdlc->shift_reg >>= 1;
@@ -474,11 +493,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
case HDLC_SEND_CRC1:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
+ if (hdlc->hdlc_bits1 == 5) {
hdlc->hdlc_bits1 = 0;
break;
}
- if(hdlc->shift_reg & 0x01){
+ if (hdlc->shift_reg & 0x01) {
hdlc->hdlc_bits1++;
hdlc->cbin++;
hdlc->shift_reg >>= 1;
@@ -488,7 +507,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->shift_reg >>= 1;
hdlc->bit_shift--;
}
- if(hdlc->bit_shift==0){
+ if (hdlc->bit_shift == 0) {
hdlc->shift_reg = (hdlc->crc >> 8);
hdlc->state = HDLC_SEND_CRC2;
hdlc->bit_shift = 8;
@@ -497,11 +516,11 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
case HDLC_SEND_CRC2:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
+ if (hdlc->hdlc_bits1 == 5) {
hdlc->hdlc_bits1 = 0;
break;
}
- if(hdlc->shift_reg & 0x01){
+ if (hdlc->shift_reg & 0x01) {
hdlc->hdlc_bits1++;
hdlc->cbin++;
hdlc->shift_reg >>= 1;
@@ -511,7 +530,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->shift_reg >>= 1;
hdlc->bit_shift--;
}
- if(hdlc->bit_shift==0){
+ if (hdlc->bit_shift == 0) {
hdlc->shift_reg = 0x7e;
hdlc->state = HDLC_SEND_CLOSING_FLAG;
hdlc->bit_shift = 8;
@@ -520,33 +539,36 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
case HDLC_SEND_CLOSING_FLAG:
hdlc->cbin <<= 1;
hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
+ if (hdlc->hdlc_bits1 == 5) {
hdlc->hdlc_bits1 = 0;
break;
}
- if(hdlc->shift_reg & 0x01){
+ if (hdlc->shift_reg & 0x01)
hdlc->cbin++;
- }
hdlc->shift_reg >>= 1;
hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
- hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
- if(hdlc->dchannel){
+ if (hdlc->bit_shift == 0) {
+ hdlc->ffvalue =
+ xfast_flag_value[hdlc->data_bits];
+ if (hdlc->dchannel) {
hdlc->ffvalue = 0x7e;
hdlc->state = HDLC_SEND_IDLE1;
hdlc->bit_shift = 8-hdlc->data_bits;
- if(hdlc->bit_shift==0)
- hdlc->state = HDLC_SEND_FAST_IDLE;
+ if (hdlc->bit_shift == 0)
+ hdlc->state =
+ HDLC_SEND_FAST_IDLE;
} else {
- if(!hdlc->do_adapt56){
- hdlc->state = HDLC_SEND_FAST_FLAG;
+ if (!hdlc->do_adapt56) {
+ hdlc->state =
+ HDLC_SEND_FAST_FLAG;
hdlc->data_received = 0;
} else {
hdlc->state = HDLC_SENDFLAG_B0;
hdlc->data_received = 0;
}
- // Finished with this frame, send flags
- if (dsize > 1) dsize = 1;
+ /* Finished this frame, send flags */
+ if (dsize > 1)
+ dsize = 1;
}
}
break;
@@ -556,7 +578,7 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->cbin++;
hdlc->data_bits++;
hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
+ if (hdlc->bit_shift == 0) {
hdlc->state = HDLC_SEND_FAST_IDLE;
hdlc->bit_shift = 0;
}
@@ -565,12 +587,17 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
hdlc->do_closing = 0;
hdlc->cbin = 0xff;
hdlc->data_bits = 8;
- if(hdlc->bit_shift == 8){
+ if (hdlc->bit_shift == 8) {
hdlc->cbin = 0x7e;
hdlc->state = HDLC_SEND_FIRST_FLAG;
} else {
- *dst++ = hdlc->cbin;
- hdlc->bit_shift = hdlc->data_bits = 0;
+ /* the code is for bitreverse streams */
+ if (hdlc->do_bitreverse == 0)
+ *dst++ = bitrev8(hdlc->cbin);
+ else
+ *dst++ = hdlc->cbin;
+ hdlc->bit_shift = 0;
+ hdlc->data_bits = 0;
len++;
dsize = 0;
}
@@ -578,15 +605,19 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
default:
break;
}
- if(hdlc->do_adapt56){
- if(hdlc->data_bits==7){
+ if (hdlc->do_adapt56) {
+ if (hdlc->data_bits == 7) {
hdlc->cbin <<= 1;
hdlc->cbin++;
hdlc->data_bits++;
}
}
- if(hdlc->data_bits==8){
- *dst++ = hdlc->cbin;
+ if (hdlc->data_bits == 8) {
+ /* the code is for bitreverse streams */
+ if (hdlc->do_bitreverse == 0)
+ *dst++ = bitrev8(hdlc->cbin);
+ else
+ *dst++ = hdlc->cbin;
hdlc->data_bits = 0;
len++;
dsize--;
@@ -596,8 +627,4 @@ int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const unsigned char *src,
return len;
}
-
-EXPORT_SYMBOL(isdnhdlc_rcv_init);
-EXPORT_SYMBOL(isdnhdlc_decode);
-EXPORT_SYMBOL(isdnhdlc_out_init);
EXPORT_SYMBOL(isdnhdlc_encode);
diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c
index 0481a0cdf6d..e8049be552a 100644
--- a/drivers/isdn/mISDN/hwchannel.c
+++ b/drivers/isdn/mISDN/hwchannel.c
@@ -114,13 +114,14 @@ mISDN_freedchannel(struct dchannel *ch)
}
EXPORT_SYMBOL(mISDN_freedchannel);
-int
-mISDN_freebchannel(struct bchannel *ch)
+void
+mISDN_clear_bchannel(struct bchannel *ch)
{
if (ch->tx_skb) {
dev_kfree_skb(ch->tx_skb);
ch->tx_skb = NULL;
}
+ ch->tx_idx = 0;
if (ch->rx_skb) {
dev_kfree_skb(ch->rx_skb);
ch->rx_skb = NULL;
@@ -129,6 +130,16 @@ mISDN_freebchannel(struct bchannel *ch)
dev_kfree_skb(ch->next_skb);
ch->next_skb = NULL;
}
+ test_and_clear_bit(FLG_TX_BUSY, &ch->Flags);
+ test_and_clear_bit(FLG_TX_NEXT, &ch->Flags);
+ test_and_clear_bit(FLG_ACTIVE, &ch->Flags);
+}
+EXPORT_SYMBOL(mISDN_clear_bchannel);
+
+int
+mISDN_freebchannel(struct bchannel *ch)
+{
+ mISDN_clear_bchannel(ch);
skb_queue_purge(&ch->rqueue);
ch->rcount = 0;
flush_scheduled_work();
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index 9c2589e986d..e17f0044e0b 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -1832,8 +1832,6 @@ static struct FsmNode L2FnList[] =
{ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
};
-#define L2_FN_COUNT (sizeof(L2FnList)/sizeof(struct FsmNode))
-
static int
ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb)
{
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 9b60b6b684d..7c8e7122aaa 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -75,6 +75,7 @@ config LEDS_ALIX2
depends on LEDS_CLASS && X86 && EXPERIMENTAL
help
This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
+ You have to set leds-alix2.force=1 for boards with Award BIOS.
config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
@@ -145,15 +146,16 @@ config LEDS_GPIO_OF
of_platform devices. For instance, LEDs which are listed in a "dts"
file.
-config LEDS_LP5521
- tristate "LED Support for the LP5521 LEDs"
+config LEDS_LP3944
+ tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip"
depends on LEDS_CLASS && I2C
help
- If you say 'Y' here you get support for the National Semiconductor
- LP5521 LED driver used in n8x0 boards.
+ This option enables support for LEDs connected to the National
+ Semiconductor LP3944 Lighting Management Unit (LMU) also known as
+ Fun Light Chip.
- This driver can be built as a module by choosing 'M'. The module
- will be called leds-lp5521.
+ To compile this driver as a module, choose M here: the
+ module will be called leds-lp3944.
config LEDS_CLEVO_MAIL
tristate "Mail LED on Clevo notebook"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 2d41c4dcf92..e8cdcf77a4c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
+obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o
obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o
obj-$(CONFIG_LEDS_FSG) += leds-fsg.o
diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c
index ddbd7730dfc..731d4eef342 100644
--- a/drivers/leds/leds-alix2.c
+++ b/drivers/leds/leds-alix2.c
@@ -14,7 +14,7 @@
static int force = 0;
module_param(force, bool, 0444);
-MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs");
+MODULE_PARM_DESC(force, "Assume system has ALIX.2/ALIX.3 style LEDs");
struct alix_led {
struct led_classdev cdev;
@@ -155,6 +155,11 @@ static int __init alix_led_init(void)
goto out;
}
+ /* enable output on GPIO for LED 1,2,3 */
+ outl(1 << 6, 0x6104);
+ outl(1 << 9, 0x6184);
+ outl(1 << 11, 0x6184);
+
pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
if (!IS_ERR(pdev)) {
ret = platform_driver_probe(&alix_led_driver, alix_led_probe);
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 4149ecb3a9b..779d7f262c0 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -97,6 +97,10 @@ struct bd2802_led {
enum led_ids led_id;
enum led_colors color;
enum led_bits state;
+
+ /* General attributes of RGB LEDs */
+ int wave_pattern;
+ int rgb_current;
};
@@ -254,7 +258,7 @@ static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
bd2802_reset_cancel(led);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
- bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
+ bd2802_write_byte(led->client, reg, led->rgb_current);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
@@ -275,9 +279,9 @@ static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
- bd2802_write_byte(led->client, reg, BD2802_CURRENT_032);
+ bd2802_write_byte(led->client, reg, led->rgb_current);
reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
- bd2802_write_byte(led->client, reg, BD2802_PATTERN_HALF);
+ bd2802_write_byte(led->client, reg, led->wave_pattern);
bd2802_enable(led, id);
bd2802_update_state(led, id, color, BD2802_BLINK);
@@ -406,7 +410,7 @@ static void bd2802_enable_adv_conf(struct bd2802_led *led)
ret = device_create_file(&led->client->dev,
bd2802_addr_attributes[i]);
if (ret) {
- dev_err(&led->client->dev, "failed to sysfs file %s\n",
+ dev_err(&led->client->dev, "failed: sysfs file %s\n",
bd2802_addr_attributes[i]->attr.name);
goto failed_remove_files;
}
@@ -483,6 +487,52 @@ static struct device_attribute bd2802_adv_conf_attr = {
.store = bd2802_store_adv_conf,
};
+#define BD2802_CONTROL_ATTR(attr_name, name_str) \
+static ssize_t bd2802_show_##attr_name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
+ ssize_t ret; \
+ down_read(&led->rwsem); \
+ ret = sprintf(buf, "0x%02x\n", led->attr_name); \
+ up_read(&led->rwsem); \
+ return ret; \
+} \
+static ssize_t bd2802_store_##attr_name(struct device *dev, \
+ struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
+ unsigned long val; \
+ int ret; \
+ if (!count) \
+ return -EINVAL; \
+ ret = strict_strtoul(buf, 16, &val); \
+ if (ret) \
+ return ret; \
+ down_write(&led->rwsem); \
+ led->attr_name = val; \
+ up_write(&led->rwsem); \
+ return count; \
+} \
+static struct device_attribute bd2802_##attr_name##_attr = { \
+ .attr = { \
+ .name = name_str, \
+ .mode = 0644, \
+ .owner = THIS_MODULE \
+ }, \
+ .show = bd2802_show_##attr_name, \
+ .store = bd2802_store_##attr_name, \
+};
+
+BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
+BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
+
+static struct device_attribute *bd2802_attributes[] = {
+ &bd2802_adv_conf_attr,
+ &bd2802_wave_pattern_attr,
+ &bd2802_rgb_current_attr,
+};
+
static void bd2802_led_work(struct work_struct *work)
{
struct bd2802_led *led = container_of(work, struct bd2802_led, work);
@@ -538,7 +588,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1r.brightness = LED_OFF;
led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
- led->cdev_led1r.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
if (ret < 0) {
@@ -551,7 +600,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1g.brightness = LED_OFF;
led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
- led->cdev_led1g.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
if (ret < 0) {
@@ -564,7 +612,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1b.brightness = LED_OFF;
led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
- led->cdev_led1b.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
if (ret < 0) {
@@ -577,7 +624,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2r.brightness = LED_OFF;
led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
- led->cdev_led2r.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
if (ret < 0) {
@@ -590,7 +636,6 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2g.brightness = LED_OFF;
led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
- led->cdev_led2g.flags |= LED_CORE_SUSPENDRESUME;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
if (ret < 0) {
@@ -640,7 +685,7 @@ static int __devinit bd2802_probe(struct i2c_client *client,
{
struct bd2802_led *led;
struct bd2802_led_platform_data *pdata;
- int ret;
+ int ret, i;
led = kzalloc(sizeof(struct bd2802_led), GFP_KERNEL);
if (!led) {
@@ -670,13 +715,20 @@ static int __devinit bd2802_probe(struct i2c_client *client,
/* To save the power, reset BD2802 after detecting */
gpio_set_value(led->pdata->reset_gpio, 0);
+ /* Default attributes */
+ led->wave_pattern = BD2802_PATTERN_HALF;
+ led->rgb_current = BD2802_CURRENT_032;
+
init_rwsem(&led->rwsem);
- ret = device_create_file(&client->dev, &bd2802_adv_conf_attr);
- if (ret) {
- dev_err(&client->dev, "failed to create sysfs file %s\n",
- bd2802_adv_conf_attr.attr.name);
- goto failed_free;
+ for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
+ ret = device_create_file(&led->client->dev,
+ bd2802_attributes[i]);
+ if (ret) {
+ dev_err(&led->client->dev, "failed: sysfs file %s\n",
+ bd2802_attributes[i]->attr.name);
+ goto failed_unregister_dev_file;
+ }
}
ret = bd2802_register_led_classdev(led);
@@ -686,7 +738,8 @@ static int __devinit bd2802_probe(struct i2c_client *client,
return 0;
failed_unregister_dev_file:
- device_remove_file(&client->dev, &bd2802_adv_conf_attr);
+ for (i--; i >= 0; i--)
+ device_remove_file(&led->client->dev, bd2802_attributes[i]);
failed_free:
i2c_set_clientdata(client, NULL);
kfree(led);
@@ -697,12 +750,14 @@ failed_free:
static int __exit bd2802_remove(struct i2c_client *client)
{
struct bd2802_led *led = i2c_get_clientdata(client);
+ int i;
- bd2802_unregister_led_classdev(led);
gpio_set_value(led->pdata->reset_gpio, 0);
+ bd2802_unregister_led_classdev(led);
if (led->adf_on)
bd2802_disable_adv_conf(led);
- device_remove_file(&client->dev, &bd2802_adv_conf_attr);
+ for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
+ device_remove_file(&led->client->dev, bd2802_attributes[i]);
i2c_set_clientdata(client, NULL);
kfree(led);
@@ -723,8 +778,7 @@ static int bd2802_resume(struct i2c_client *client)
struct bd2802_led *led = i2c_get_clientdata(client);
if (!bd2802_is_all_off(led) || led->adf_on) {
- gpio_set_value(led->pdata->reset_gpio, 1);
- udelay(100);
+ bd2802_reset_cancel(led);
bd2802_restore_state(led);
}
@@ -762,4 +816,4 @@ module_exit(bd2802_exit);
MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
MODULE_DESCRIPTION("BD2802 LED driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c
index ff0e8c3fbf9..5f1ce810815 100644
--- a/drivers/leds/leds-cobalt-raq.c
+++ b/drivers/leds/leds-cobalt-raq.c
@@ -1,7 +1,7 @@
/*
* LEDs driver for the Cobalt Raq series.
*
- * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2007 Yoichi Yuasa <yuasa@linux-mips.org>
*
* 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
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index d2109054de8..6b06638eb5b 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -76,7 +76,7 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
int (*blink_set)(unsigned, unsigned long *, unsigned long *))
{
- int ret;
+ int ret, state;
/* skip leds that aren't available */
if (!gpio_is_valid(template->gpio)) {
@@ -99,11 +99,15 @@ static int __devinit create_gpio_led(const struct gpio_led *template,
led_dat->cdev.blink_set = gpio_blink_set;
}
led_dat->cdev.brightness_set = gpio_led_set;
- led_dat->cdev.brightness = LED_OFF;
+ if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
+ state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low;
+ else
+ state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
+ led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- ret = gpio_direction_output(led_dat->gpio, led_dat->active_low);
+ ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
if (ret < 0)
goto err;
@@ -129,7 +133,7 @@ static void delete_gpio_led(struct gpio_led_data *led)
}
#ifdef CONFIG_LEDS_GPIO_PLATFORM
-static int gpio_led_probe(struct platform_device *pdev)
+static int __devinit gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_led_data *leds_data;
@@ -223,12 +227,22 @@ static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
memset(&led, 0, sizeof(led));
for_each_child_of_node(np, child) {
enum of_gpio_flags flags;
+ const char *state;
led.gpio = of_get_gpio_flags(child, 0, &flags);
led.active_low = flags & OF_GPIO_ACTIVE_LOW;
led.name = of_get_property(child, "label", NULL) ? : child->name;
led.default_trigger =
of_get_property(child, "linux,default-trigger", NULL);
+ state = of_get_property(child, "default-state", NULL);
+ if (state) {
+ if (!strcmp(state, "keep"))
+ led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
+ else if(!strcmp(state, "on"))
+ led.default_state = LEDS_GPIO_DEFSTATE_ON;
+ else
+ led.default_state = LEDS_GPIO_DEFSTATE_OFF;
+ }
ret = create_gpio_led(&led, &pdata->led_data[pdata->num_leds++],
&ofdev->dev, NULL);
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
new file mode 100644
index 00000000000..5946208ba26
--- /dev/null
+++ b/drivers/leds/leds-lp3944.c
@@ -0,0 +1,466 @@
+/*
+ * leds-lp3944.c - driver for National Semiconductor LP3944 Funlight Chip
+ *
+ * Copyright (C) 2009 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * 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.
+ *
+ */
+
+/*
+ * I2C driver for National Semiconductor LP3944 Funlight Chip
+ * http://www.national.com/pf/LP/LP3944.html
+ *
+ * This helper chip can drive up to 8 leds, with two programmable DIM modes;
+ * it could even be used as a gpio expander but this driver assumes it is used
+ * as a led controller.
+ *
+ * The DIM modes are used to set _blink_ patterns for leds, the pattern is
+ * specified supplying two parameters:
+ * - period: from 0s to 1.6s
+ * - duty cycle: percentage of the period the led is on, from 0 to 100
+ *
+ * LP3944 can be found on Motorola A910 smartphone, where it drives the rgb
+ * leds, the camera flash light and the displays backlights.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/leds-lp3944.h>
+
+/* Read Only Registers */
+#define LP3944_REG_INPUT1 0x00 /* LEDs 0-7 InputRegister (Read Only) */
+#define LP3944_REG_REGISTER1 0x01 /* None (Read Only) */
+
+#define LP3944_REG_PSC0 0x02 /* Frequency Prescaler 0 (R/W) */
+#define LP3944_REG_PWM0 0x03 /* PWM Register 0 (R/W) */
+#define LP3944_REG_PSC1 0x04 /* Frequency Prescaler 1 (R/W) */
+#define LP3944_REG_PWM1 0x05 /* PWM Register 1 (R/W) */
+#define LP3944_REG_LS0 0x06 /* LEDs 0-3 Selector (R/W) */
+#define LP3944_REG_LS1 0x07 /* LEDs 4-7 Selector (R/W) */
+
+/* These registers are not used to control leds in LP3944, they can store
+ * arbitrary values which the chip will ignore.
+ */
+#define LP3944_REG_REGISTER8 0x08
+#define LP3944_REG_REGISTER9 0x09
+
+#define LP3944_DIM0 0
+#define LP3944_DIM1 1
+
+/* period in ms */
+#define LP3944_PERIOD_MIN 0
+#define LP3944_PERIOD_MAX 1600
+
+/* duty cycle is a percentage */
+#define LP3944_DUTY_CYCLE_MIN 0
+#define LP3944_DUTY_CYCLE_MAX 100
+
+#define ldev_to_led(c) container_of(c, struct lp3944_led_data, ldev)
+
+/* Saved data */
+struct lp3944_led_data {
+ u8 id;
+ enum lp3944_type type;
+ enum lp3944_status status;
+ struct led_classdev ldev;
+ struct i2c_client *client;
+ struct work_struct work;
+};
+
+struct lp3944_data {
+ struct mutex lock;
+ struct i2c_client *client;
+ struct lp3944_led_data leds[LP3944_LEDS_MAX];
+};
+
+static int lp3944_reg_read(struct i2c_client *client, u8 reg, u8 *value)
+{
+ int tmp;
+
+ tmp = i2c_smbus_read_byte_data(client, reg);
+ if (tmp < 0)
+ return -EINVAL;
+
+ *value = tmp;
+
+ return 0;
+}
+
+static int lp3944_reg_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+/**
+ * Set the period for DIM status
+ *
+ * @client: the i2c client
+ * @dim: either LP3944_DIM0 or LP3944_DIM1
+ * @period: period of a blink, that is a on/off cycle, expressed in ms.
+ */
+static int lp3944_dim_set_period(struct i2c_client *client, u8 dim, u16 period)
+{
+ u8 psc_reg;
+ u8 psc_value;
+ int err;
+
+ if (dim == LP3944_DIM0)
+ psc_reg = LP3944_REG_PSC0;
+ else if (dim == LP3944_DIM1)
+ psc_reg = LP3944_REG_PSC1;
+ else
+ return -EINVAL;
+
+ /* Convert period to Prescaler value */
+ if (period > LP3944_PERIOD_MAX)
+ return -EINVAL;
+
+ psc_value = (period * 255) / LP3944_PERIOD_MAX;
+
+ err = lp3944_reg_write(client, psc_reg, psc_value);
+
+ return err;
+}
+
+/**
+ * Set the duty cycle for DIM status
+ *
+ * @client: the i2c client
+ * @dim: either LP3944_DIM0 or LP3944_DIM1
+ * @duty_cycle: percentage of a period during which a led is ON
+ */
+static int lp3944_dim_set_dutycycle(struct i2c_client *client, u8 dim,
+ u8 duty_cycle)
+{
+ u8 pwm_reg;
+ u8 pwm_value;
+ int err;
+
+ if (dim == LP3944_DIM0)
+ pwm_reg = LP3944_REG_PWM0;
+ else if (dim == LP3944_DIM1)
+ pwm_reg = LP3944_REG_PWM1;
+ else
+ return -EINVAL;
+
+ /* Convert duty cycle to PWM value */
+ if (duty_cycle > LP3944_DUTY_CYCLE_MAX)
+ return -EINVAL;
+
+ pwm_value = (duty_cycle * 255) / LP3944_DUTY_CYCLE_MAX;
+
+ err = lp3944_reg_write(client, pwm_reg, pwm_value);
+
+ return err;
+}
+
+/**
+ * Set the led status
+ *
+ * @led: a lp3944_led_data structure
+ * @status: one of LP3944_LED_STATUS_OFF
+ * LP3944_LED_STATUS_ON
+ * LP3944_LED_STATUS_DIM0
+ * LP3944_LED_STATUS_DIM1
+ */
+static int lp3944_led_set(struct lp3944_led_data *led, u8 status)
+{
+ struct lp3944_data *data = i2c_get_clientdata(led->client);
+ u8 id = led->id;
+ u8 reg;
+ u8 val = 0;
+ int err;
+
+ dev_dbg(&led->client->dev, "%s: %s, status before normalization:%d\n",
+ __func__, led->ldev.name, status);
+
+ switch (id) {
+ case LP3944_LED0:
+ case LP3944_LED1:
+ case LP3944_LED2:
+ case LP3944_LED3:
+ reg = LP3944_REG_LS0;
+ break;
+ case LP3944_LED4:
+ case LP3944_LED5:
+ case LP3944_LED6:
+ case LP3944_LED7:
+ id -= LP3944_LED4;
+ reg = LP3944_REG_LS1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (status > LP3944_LED_STATUS_DIM1)
+ return -EINVAL;
+
+ /* invert only 0 and 1, leave unchanged the other values,
+ * remember we are abusing status to set blink patterns
+ */
+ if (led->type == LP3944_LED_TYPE_LED_INVERTED && status < 2)
+ status = 1 - status;
+
+ mutex_lock(&data->lock);
+ lp3944_reg_read(led->client, reg, &val);
+
+ val &= ~(LP3944_LED_STATUS_MASK << (id << 1));
+ val |= (status << (id << 1));
+
+ dev_dbg(&led->client->dev, "%s: %s, reg:%d id:%d status:%d val:%#x\n",
+ __func__, led->ldev.name, reg, id, status, val);
+
+ /* set led status */
+ err = lp3944_reg_write(led->client, reg, val);
+ mutex_unlock(&data->lock);
+
+ return err;
+}
+
+static int lp3944_led_set_blink(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct lp3944_led_data *led = ldev_to_led(led_cdev);
+ u16 period;
+ u8 duty_cycle;
+ int err;
+
+ /* units are in ms */
+ if (*delay_on + *delay_off > LP3944_PERIOD_MAX)
+ return -EINVAL;
+
+ if (*delay_on == 0 && *delay_off == 0) {
+ /* Special case: the leds subsystem requires a default user
+ * friendly blink pattern for the LED. Let's blink the led
+ * slowly (1Hz).
+ */
+ *delay_on = 500;
+ *delay_off = 500;
+ }
+
+ period = (*delay_on) + (*delay_off);
+
+ /* duty_cycle is the percentage of period during which the led is ON */
+ duty_cycle = 100 * (*delay_on) / period;
+
+ /* invert duty cycle for inverted leds, this has the same effect of
+ * swapping delay_on and delay_off
+ */
+ if (led->type == LP3944_LED_TYPE_LED_INVERTED)
+ duty_cycle = 100 - duty_cycle;
+
+ /* NOTE: using always the first DIM mode, this means that all leds
+ * will have the same blinking pattern.
+ *
+ * We could find a way later to have two leds blinking in hardware
+ * with different patterns at the same time, falling back to software
+ * control for the other ones.
+ */
+ err = lp3944_dim_set_period(led->client, LP3944_DIM0, period);
+ if (err)
+ return err;
+
+ err = lp3944_dim_set_dutycycle(led->client, LP3944_DIM0, duty_cycle);
+ if (err)
+ return err;
+
+ dev_dbg(&led->client->dev, "%s: OK hardware accelerated blink!\n",
+ __func__);
+
+ led->status = LP3944_LED_STATUS_DIM0;
+ schedule_work(&led->work);
+
+ return 0;
+}
+
+static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct lp3944_led_data *led = ldev_to_led(led_cdev);
+
+ dev_dbg(&led->client->dev, "%s: %s, %d\n",
+ __func__, led_cdev->name, brightness);
+
+ led->status = brightness;
+ schedule_work(&led->work);
+}
+
+static void lp3944_led_work(struct work_struct *work)
+{
+ struct lp3944_led_data *led;
+
+ led = container_of(work, struct lp3944_led_data, work);
+ lp3944_led_set(led, led->status);
+}
+
+static int lp3944_configure(struct i2c_client *client,
+ struct lp3944_data *data,
+ struct lp3944_platform_data *pdata)
+{
+ int i, err = 0;
+
+ for (i = 0; i < pdata->leds_size; i++) {
+ struct lp3944_led *pled = &pdata->leds[i];
+ struct lp3944_led_data *led = &data->leds[i];
+ led->client = client;
+ led->id = i;
+
+ switch (pled->type) {
+
+ case LP3944_LED_TYPE_LED:
+ case LP3944_LED_TYPE_LED_INVERTED:
+ led->type = pled->type;
+ led->status = pled->status;
+ led->ldev.name = pled->name;
+ led->ldev.max_brightness = 1;
+ led->ldev.brightness_set = lp3944_led_set_brightness;
+ led->ldev.blink_set = lp3944_led_set_blink;
+ led->ldev.flags = LED_CORE_SUSPENDRESUME;
+
+ INIT_WORK(&led->work, lp3944_led_work);
+ err = led_classdev_register(&client->dev, &led->ldev);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "couldn't register LED %s\n",
+ led->ldev.name);
+ goto exit;
+ }
+
+ /* to expose the default value to userspace */
+ led->ldev.brightness = led->status;
+
+ /* Set the default led status */
+ err = lp3944_led_set(led, led->status);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "%s couldn't set STATUS %d\n",
+ led->ldev.name, led->status);
+ goto exit;
+ }
+ break;
+
+ case LP3944_LED_TYPE_NONE:
+ default:
+ break;
+
+ }
+ }
+ return 0;
+
+exit:
+ if (i > 0)
+ for (i = i - 1; i >= 0; i--)
+ switch (pdata->leds[i].type) {
+
+ case LP3944_LED_TYPE_LED:
+ case LP3944_LED_TYPE_LED_INVERTED:
+ led_classdev_unregister(&data->leds[i].ldev);
+ cancel_work_sync(&data->leds[i].work);
+ break;
+
+ case LP3944_LED_TYPE_NONE:
+ default:
+ break;
+ }
+
+ return err;
+}
+
+static int __devinit lp3944_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data;
+ struct lp3944_data *data;
+
+ if (lp3944_pdata == NULL) {
+ dev_err(&client->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ /* Let's see whether this adapter can support what we need. */
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "insufficient functionality!\n");
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(struct lp3944_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->client = client;
+ i2c_set_clientdata(client, data);
+
+ mutex_init(&data->lock);
+
+ dev_info(&client->dev, "lp3944 enabled\n");
+
+ lp3944_configure(client, data, lp3944_pdata);
+ return 0;
+}
+
+static int __devexit lp3944_remove(struct i2c_client *client)
+{
+ struct lp3944_platform_data *pdata = client->dev.platform_data;
+ struct lp3944_data *data = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < pdata->leds_size; i++)
+ switch (data->leds[i].type) {
+ case LP3944_LED_TYPE_LED:
+ case LP3944_LED_TYPE_LED_INVERTED:
+ led_classdev_unregister(&data->leds[i].ldev);
+ cancel_work_sync(&data->leds[i].work);
+ break;
+
+ case LP3944_LED_TYPE_NONE:
+ default:
+ break;
+ }
+
+ kfree(data);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+/* lp3944 i2c driver struct */
+static const struct i2c_device_id lp3944_id[] = {
+ {"lp3944", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lp3944_id);
+
+static struct i2c_driver lp3944_driver = {
+ .driver = {
+ .name = "lp3944",
+ },
+ .probe = lp3944_probe,
+ .remove = __devexit_p(lp3944_remove),
+ .id_table = lp3944_id,
+};
+
+static int __init lp3944_module_init(void)
+{
+ return i2c_add_driver(&lp3944_driver);
+}
+
+static void __exit lp3944_module_exit(void)
+{
+ i2c_del_driver(&lp3944_driver);
+}
+
+module_init(lp3944_module_init);
+module_exit(lp3944_module_exit);
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("LP3944 Fun Light Chip");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 3937244fdca..dba8921240f 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -35,7 +35,7 @@ struct pca9532_data {
struct pca9532_led leds[16];
struct mutex update_lock;
struct input_dev *idev;
- struct work_struct work;
+ struct work_struct work;
u8 pwm[2];
u8 psc[2];
};
@@ -87,14 +87,14 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
if (b > 0xFF)
return -EINVAL;
data->pwm[pwm] = b;
- data->psc[pwm] = blink;
- return 0;
+ data->psc[pwm] = blink;
+ return 0;
}
static int pca9532_setpwm(struct i2c_client *client, int pwm)
{
- struct pca9532_data *data = i2c_get_clientdata(client);
- mutex_lock(&data->update_lock);
+ struct pca9532_data *data = i2c_get_clientdata(client);
+ mutex_lock(&data->update_lock);
i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
data->pwm[pwm]);
i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
@@ -132,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
led->state = PCA9532_ON;
else {
led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
- err = pca9532_calcpwm(led->client, 0, 0, value);
+ err = pca9532_calcpwm(led->client, 0, 0, value);
if (err)
return; /* XXX: led api doesn't allow error code? */
}
- schedule_work(&led->work);
+ schedule_work(&led->work);
}
static int pca9532_set_blink(struct led_classdev *led_cdev,
@@ -145,7 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
struct pca9532_led *led = ldev_to_led(led_cdev);
struct i2c_client *client = led->client;
int psc;
- int err = 0;
+ int err = 0;
if (*delay_on == 0 && *delay_off == 0) {
/* led subsystem ask us for a blink rate */
@@ -157,11 +157,11 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
/* Thecus specific: only use PSC/PWM 0 */
psc = (*delay_on * 152-1)/1000;
- err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
- if (err)
- return err;
- schedule_work(&led->work);
- return 0;
+ err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
+ if (err)
+ return err;
+ schedule_work(&led->work);
+ return 0;
}
static int pca9532_event(struct input_dev *dev, unsigned int type,
@@ -178,15 +178,15 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
else
data->pwm[1] = 0;
- schedule_work(&data->work);
+ schedule_work(&data->work);
- return 0;
+ return 0;
}
static void pca9532_input_work(struct work_struct *work)
{
- struct pca9532_data *data;
- data = container_of(work, struct pca9532_data, work);
+ struct pca9532_data *data;
+ data = container_of(work, struct pca9532_data, work);
mutex_lock(&data->update_lock);
i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
data->pwm[1]);
@@ -195,11 +195,11 @@ static void pca9532_input_work(struct work_struct *work)
static void pca9532_led_work(struct work_struct *work)
{
- struct pca9532_led *led;
- led = container_of(work, struct pca9532_led, work);
- if (led->state == PCA9532_PWM0)
- pca9532_setpwm(led->client, 0);
- pca9532_setled(led);
+ struct pca9532_led *led;
+ led = container_of(work, struct pca9532_led, work);
+ if (led->state == PCA9532_PWM0)
+ pca9532_setpwm(led->client, 0);
+ pca9532_setled(led);
}
static int pca9532_configure(struct i2c_client *client,
@@ -232,7 +232,7 @@ static int pca9532_configure(struct i2c_client *client,
led->ldev.brightness = LED_OFF;
led->ldev.brightness_set = pca9532_set_brightness;
led->ldev.blink_set = pca9532_set_blink;
- INIT_WORK(&led->work, pca9532_led_work);
+ INIT_WORK(&led->work, pca9532_led_work);
err = led_classdev_register(&client->dev, &led->ldev);
if (err < 0) {
dev_err(&client->dev,
@@ -262,11 +262,11 @@ static int pca9532_configure(struct i2c_client *client,
BIT_MASK(SND_TONE);
data->idev->event = pca9532_event;
input_set_drvdata(data->idev, data);
- INIT_WORK(&data->work, pca9532_input_work);
+ INIT_WORK(&data->work, pca9532_input_work);
err = input_register_device(data->idev);
if (err) {
input_free_device(data->idev);
- cancel_work_sync(&data->work);
+ cancel_work_sync(&data->work);
data->idev = NULL;
goto exit;
}
@@ -283,13 +283,13 @@ exit:
break;
case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev);
- cancel_work_sync(&data->leds[i].work);
+ cancel_work_sync(&data->leds[i].work);
break;
case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) {
input_unregister_device(data->idev);
input_free_device(data->idev);
- cancel_work_sync(&data->work);
+ cancel_work_sync(&data->work);
data->idev = NULL;
}
break;
@@ -340,13 +340,13 @@ static int pca9532_remove(struct i2c_client *client)
break;
case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev);
- cancel_work_sync(&data->leds[i].work);
+ cancel_work_sync(&data->leds[i].work);
break;
case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) {
input_unregister_device(data->idev);
input_free_device(data->idev);
- cancel_work_sync(&data->work);
+ cancel_work_sync(&data->work);
data->idev = NULL;
}
break;
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index d4e8979735c..9c3138265f8 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -82,7 +82,7 @@ struct lg_cpu {
struct lg_eventfd {
unsigned long addr;
- struct file *event;
+ struct eventfd_ctx *event;
};
struct lg_eventfd_map {
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 32e29712105..9f9a2953b38 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -50,7 +50,7 @@ static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
/* Now append new entry. */
new->map[new->num].addr = addr;
- new->map[new->num].event = eventfd_fget(fd);
+ new->map[new->num].event = eventfd_ctx_fdget(fd);
if (IS_ERR(new->map[new->num].event)) {
kfree(new);
return PTR_ERR(new->map[new->num].event);
@@ -357,7 +357,7 @@ static int close(struct inode *inode, struct file *file)
/* Release any eventfds they registered. */
for (i = 0; i < lg->eventfds->num; i++)
- fput(lg->eventfds->map[i].event);
+ eventfd_ctx_put(lg->eventfds->map[i].event);
kfree(lg->eventfds);
/* If lg->dead doesn't contain an error code it will be NULL or a
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 6e149f4a1ff..a0f68386c12 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -378,6 +378,17 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
dev->ofdev.dev.bus = &macio_bus_type;
dev->ofdev.dev.release = macio_release_dev;
+#ifdef CONFIG_PCI
+ /* Set the DMA ops to the ones from the PCI device, this could be
+ * fishy if we didn't know that on PowerMac it's always direct ops
+ * or iommu ops that will work fine
+ */
+ dev->ofdev.dev.archdata.dma_ops =
+ chip->lbus.pdev->dev.archdata.dma_ops;
+ dev->ofdev.dev.archdata.dma_data =
+ chip->lbus.pdev->dev.archdata.dma_data;
+#endif /* CONFIG_PCI */
+
#ifdef DEBUG
printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n",
dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj);
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index c3ae51584b1..3710ff88fc1 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -195,7 +195,7 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
struct dm_exception_store **store)
{
int r = 0;
- struct dm_exception_store_type *type;
+ struct dm_exception_store_type *type = NULL;
struct dm_exception_store *tmp_store;
char persistent;
@@ -211,12 +211,15 @@ int dm_exception_store_create(struct dm_target *ti, int argc, char **argv,
}
persistent = toupper(*argv[1]);
- if (persistent != 'P' && persistent != 'N') {
+ if (persistent == 'P')
+ type = get_type("P");
+ else if (persistent == 'N')
+ type = get_type("N");
+ else {
ti->error = "Persistent flag is not P or N";
return -EINVAL;
}
- type = get_type(&persistent);
if (!type) {
ti->error = "Exception store type not recognised";
r = -EINVAL;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 4899ebe767c..2cba557d9e6 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -495,7 +495,7 @@ int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev,
return 0;
}
- if (blk_stack_limits(limits, &q->limits, start) < 0)
+ if (blk_stack_limits(limits, &q->limits, start << 9) < 0)
DMWARN("%s: target device %s is misaligned",
dm_device_name(ti->table->md), bdevname(bdev, b));
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 3c6d4ee8921..9acd54a5cff 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1017,7 +1017,7 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
clone->bi_flags |= 1 << BIO_CLONED;
if (bio_integrity(bio)) {
- bio_integrity_clone(clone, bio, GFP_NOIO);
+ bio_integrity_clone(clone, bio, GFP_NOIO, bs);
bio_integrity_trim(clone,
bio_sector_offset(bio, idx, offset), len);
}
@@ -1045,7 +1045,7 @@ static struct bio *clone_bio(struct bio *bio, sector_t sector,
clone->bi_flags &= ~(1 << BIO_SEG_VALID);
if (bio_integrity(bio)) {
- bio_integrity_clone(clone, bio, GFP_NOIO);
+ bio_integrity_clone(clone, bio, GFP_NOIO, bs);
if (idx != bio->bi_idx || clone->bi_size < bio->bi_size)
bio_integrity_trim(clone,
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 15c8b7b25a9..5810fa906af 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -166,8 +166,8 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
rdev->sectors = sectors * mddev->chunk_sectors;
}
- blk_queue_stack_limits(mddev->queue,
- rdev->bdev->bd_disk->queue);
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
/* as we don't honour merge_bvec_fn, we must never risk
* violating it, so limit ->max_sector to one PAGE, as
* a one page request is never in violation.
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 09be637d52c..0f4a70c43ff 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3573,7 +3573,8 @@ suspend_lo_store(mddev_t *mddev, const char *buf, size_t len)
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
- if (mddev->pers->quiesce == NULL)
+ if (mddev->pers == NULL ||
+ mddev->pers->quiesce == NULL)
return -EINVAL;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
@@ -3601,7 +3602,8 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
- if (mddev->pers->quiesce == NULL)
+ if (mddev->pers == NULL ||
+ mddev->pers->quiesce == NULL)
return -EINVAL;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
@@ -3844,11 +3846,9 @@ static int md_alloc(dev_t dev, char *name)
flush_scheduled_work();
mutex_lock(&disks_mutex);
- if (mddev->gendisk) {
- mutex_unlock(&disks_mutex);
- mddev_put(mddev);
- return -EEXIST;
- }
+ error = -EEXIST;
+ if (mddev->gendisk)
+ goto abort;
if (name) {
/* Need to ensure that 'name' is not a duplicate.
@@ -3860,17 +3860,15 @@ static int md_alloc(dev_t dev, char *name)
if (mddev2->gendisk &&
strcmp(mddev2->gendisk->disk_name, name) == 0) {
spin_unlock(&all_mddevs_lock);
- return -EEXIST;
+ goto abort;
}
spin_unlock(&all_mddevs_lock);
}
+ error = -ENOMEM;
mddev->queue = blk_alloc_queue(GFP_KERNEL);
- if (!mddev->queue) {
- mutex_unlock(&disks_mutex);
- mddev_put(mddev);
- return -ENOMEM;
- }
+ if (!mddev->queue)
+ goto abort;
mddev->queue->queuedata = mddev;
/* Can be unlocked because the queue is new: no concurrency */
@@ -3880,11 +3878,9 @@ static int md_alloc(dev_t dev, char *name)
disk = alloc_disk(1 << shift);
if (!disk) {
- mutex_unlock(&disks_mutex);
blk_cleanup_queue(mddev->queue);
mddev->queue = NULL;
- mddev_put(mddev);
- return -ENOMEM;
+ goto abort;
}
disk->major = MAJOR(mddev->unit);
disk->first_minor = unit << shift;
@@ -3906,16 +3902,22 @@ static int md_alloc(dev_t dev, char *name)
mddev->gendisk = disk;
error = kobject_init_and_add(&mddev->kobj, &md_ktype,
&disk_to_dev(disk)->kobj, "%s", "md");
- mutex_unlock(&disks_mutex);
- if (error)
+ if (error) {
+ /* This isn't possible, but as kobject_init_and_add is marked
+ * __must_check, we must do something with the result
+ */
printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
disk->disk_name);
- else {
+ error = 0;
+ }
+ abort:
+ mutex_unlock(&disks_mutex);
+ if (!error) {
kobject_uevent(&mddev->kobj, KOBJ_ADD);
mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
}
mddev_put(mddev);
- return 0;
+ return error;
}
static struct kobject *md_probe(dev_t dev, int *part, void *data)
@@ -6334,10 +6336,16 @@ void md_do_sync(mddev_t *mddev)
sysfs_notify(&mddev->kobj, NULL, "sync_completed");
}
- if (j >= mddev->resync_max)
- wait_event(mddev->recovery_wait,
- mddev->resync_max > j
- || kthread_should_stop());
+ while (j >= mddev->resync_max && !kthread_should_stop()) {
+ /* As this condition is controlled by user-space,
+ * we can block indefinitely, so use '_interruptible'
+ * to avoid triggering warnings.
+ */
+ flush_signals(current); /* just in case */
+ wait_event_interruptible(mddev->recovery_wait,
+ mddev->resync_max > j
+ || kthread_should_stop());
+ }
if (kthread_should_stop())
goto interrupted;
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index cbe368fa659..237fe3fd235 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -294,7 +294,8 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
for (path = first; path <= last; path++)
if ((p=conf->multipaths+path)->rdev == NULL) {
q = rdev->bdev->bd_disk->queue;
- blk_queue_stack_limits(mddev->queue, q);
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
/* as we don't honour merge_bvec_fn, we must never risk
* violating it, so limit ->max_sector to one PAGE, as
@@ -463,9 +464,9 @@ static int multipath_run (mddev_t *mddev)
disk = conf->multipaths + disk_idx;
disk->rdev = rdev;
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
- blk_queue_stack_limits(mddev->queue,
- rdev->bdev->bd_disk->queue);
/* as we don't honour merge_bvec_fn, we must never risk
* violating it, not that we ever expect a device with
* a merge_bvec_fn to be involved in multipath */
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index ab4a489d869..335f490dcad 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -170,8 +170,8 @@ static int create_strip_zones(mddev_t *mddev)
}
dev[j] = rdev1;
- blk_queue_stack_limits(mddev->queue,
- rdev1->bdev->bd_disk->queue);
+ disk_stack_limits(mddev->gendisk, rdev1->bdev,
+ rdev1->data_offset << 9);
/* as we don't honour merge_bvec_fn, we must never risk
* violating it, so limit ->max_sector to one PAGE, as
* a one page request is never in violation.
@@ -250,6 +250,11 @@ static int create_strip_zones(mddev_t *mddev)
mddev->chunk_sectors << 9);
goto abort;
}
+
+ blk_queue_io_min(mddev->queue, mddev->chunk_sectors << 9);
+ blk_queue_io_opt(mddev->queue,
+ (mddev->chunk_sectors << 9) * mddev->raid_disks);
+
printk(KERN_INFO "raid0: done.\n");
mddev->private = conf;
return 0;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 89939a7aef5..0569efba0c0 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1123,8 +1123,8 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
for (mirror = first; mirror <= last; mirror++)
if ( !(p=conf->mirrors+mirror)->rdev) {
- blk_queue_stack_limits(mddev->queue,
- rdev->bdev->bd_disk->queue);
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
/* as we don't honour merge_bvec_fn, we must never risk
* violating it, so limit ->max_sector to one PAGE, as
* a one page request is never in violation.
@@ -1988,9 +1988,8 @@ static int run(mddev_t *mddev)
disk = conf->mirrors + disk_idx;
disk->rdev = rdev;
-
- blk_queue_stack_limits(mddev->queue,
- rdev->bdev->bd_disk->queue);
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
/* as we don't honour merge_bvec_fn, we must never risk
* violating it, so limit ->max_sector to one PAGE, as
* a one page request is never in violation.
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index ae12ceafe10..7298a5e5a18 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1151,8 +1151,8 @@ static int raid10_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
for ( ; mirror <= last ; mirror++)
if ( !(p=conf->mirrors+mirror)->rdev) {
- blk_queue_stack_limits(mddev->queue,
- rdev->bdev->bd_disk->queue);
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
/* as we don't honour merge_bvec_fn, we must never risk
* violating it, so limit ->max_sector to one PAGE, as
* a one page request is never in violation.
@@ -2044,7 +2044,7 @@ raid10_size(mddev_t *mddev, sector_t sectors, int raid_disks)
static int run(mddev_t *mddev)
{
conf_t *conf;
- int i, disk_idx;
+ int i, disk_idx, chunk_size;
mirror_info_t *disk;
mdk_rdev_t *rdev;
int nc, fc, fo;
@@ -2130,6 +2130,14 @@ static int run(mddev_t *mddev)
spin_lock_init(&conf->device_lock);
mddev->queue->queue_lock = &conf->device_lock;
+ chunk_size = mddev->chunk_sectors << 9;
+ blk_queue_io_min(mddev->queue, chunk_size);
+ if (conf->raid_disks % conf->near_copies)
+ blk_queue_io_opt(mddev->queue, chunk_size * conf->raid_disks);
+ else
+ blk_queue_io_opt(mddev->queue, chunk_size *
+ (conf->raid_disks / conf->near_copies));
+
list_for_each_entry(rdev, &mddev->disks, same_set) {
disk_idx = rdev->raid_disk;
if (disk_idx >= mddev->raid_disks
@@ -2138,9 +2146,8 @@ static int run(mddev_t *mddev)
disk = conf->mirrors + disk_idx;
disk->rdev = rdev;
-
- blk_queue_stack_limits(mddev->queue,
- rdev->bdev->bd_disk->queue);
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
/* as we don't honour merge_bvec_fn, we must never risk
* violating it, so limit ->max_sector to one PAGE, as
* a one page request is never in violation.
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f9f991e6e13..37835538b58 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3699,13 +3699,21 @@ static int make_request(struct request_queue *q, struct bio * bi)
goto retry;
}
}
- /* FIXME what if we get a false positive because these
- * are being updated.
- */
- if (logical_sector >= mddev->suspend_lo &&
+
+ if (bio_data_dir(bi) == WRITE &&
+ logical_sector >= mddev->suspend_lo &&
logical_sector < mddev->suspend_hi) {
release_stripe(sh);
- schedule();
+ /* As the suspend_* range is controlled by
+ * userspace, we want an interruptible
+ * wait.
+ */
+ flush_signals(current);
+ prepare_to_wait(&conf->wait_for_overlap,
+ &w, TASK_INTERRUPTIBLE);
+ if (logical_sector >= mddev->suspend_lo &&
+ logical_sector < mddev->suspend_hi)
+ schedule();
goto retry;
}
@@ -4452,7 +4460,7 @@ static raid5_conf_t *setup_conf(mddev_t *mddev)
static int run(mddev_t *mddev)
{
raid5_conf_t *conf;
- int working_disks = 0;
+ int working_disks = 0, chunk_size;
mdk_rdev_t *rdev;
if (mddev->recovery_cp != MaxSector)
@@ -4607,6 +4615,14 @@ static int run(mddev_t *mddev)
md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
+ chunk_size = mddev->chunk_sectors << 9;
+ blk_queue_io_min(mddev->queue, chunk_size);
+ blk_queue_io_opt(mddev->queue, chunk_size *
+ (conf->raid_disks - conf->max_degraded));
+
+ list_for_each_entry(rdev, &mddev->disks, same_set)
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
return 0;
abort:
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 8280f8d66a3..8c9ae0a3a27 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -904,7 +904,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
{
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index a9e48e28b1d..bc2ec2182c0 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -795,7 +795,7 @@ mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev)
IOC_AND_NETDEV_NAMES_s_s(dev),
le32_to_cpu(pSimple->FlagsLength)));
- return 0;
+ return NETDEV_TX_OK;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c
index 671a7efe86a..c1de4afa89a 100644
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -238,8 +238,10 @@ static irqreturn_t pcap_adc_irq(int irq, void *_pcap)
mutex_lock(&pcap->adc_mutex);
req = pcap->adc_queue[pcap->adc_head];
- if (WARN(!req, KERN_WARNING "adc irq without pending request\n"))
+ if (WARN(!req, KERN_WARNING "adc irq without pending request\n")) {
+ mutex_unlock(&pcap->adc_mutex);
return IRQ_HANDLED;
+ }
/* read requested channels results */
ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp);
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 4c7b7962f6b..0cc5eeff5ee 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -367,7 +367,8 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to)
break;
default:
- return -1;
+ gate = -1;
+ goto already;
}
writel(mode, sm->regs + SM501_POWER_MODE_CONTROL);
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c
index 8d1c60a3f0d..b681bf8abdc 100644
--- a/drivers/misc/sgi-xp/xpnet.c
+++ b/drivers/misc/sgi-xp/xpnet.c
@@ -436,7 +436,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] == 0x33) {
dev_kfree_skb(skb);
- return 0; /* nothing needed to be done */
+ return NETDEV_TX_OK; /* nothing needed to be done */
}
/*
@@ -503,7 +503,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 240608cc7ae..a461017ce5c 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1313,6 +1313,12 @@ static int mmc_spi_probe(struct spi_device *spi)
struct mmc_spi_host *host;
int status;
+ /* We rely on full duplex transfers, mostly to reduce
+ * per-transfer overheads (by making fewer transfers).
+ */
+ if (spi->master->flags & SPI_MASTER_HALF_DUPLEX)
+ return -EINVAL;
+
/* MMC and SD specs only seem to care that sampling is on the
* rising edge ... meaning SPI modes 0 or 3. So either SPI mode
* should be legit. We'll use mode 0 since the steady state is 0,
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index 5011fa73f91..1479da6d3aa 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -194,7 +194,7 @@ static struct mtd_partition * newpart(char *s,
parts[this_part].name = extra_mem;
extra_mem += name_len + 1;
- dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+ dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n",
this_part,
parts[this_part].name,
parts[this_part].offset,
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 59c46126a5c..ae5fe91867e 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -54,7 +54,7 @@
#define SR_SRWD 0x80 /* SR write protect */
/* Define max times to check status register before we give up. */
-#define MAX_READY_WAIT_JIFFIES (10 * HZ) /* eg. M25P128 specs 6s max sector erase */
+#define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */
#define CMD_SIZE 4
#ifdef CONFIG_M25PXX_USE_FAST_READ
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 73f05227dc8..d8cf29c01cc 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -226,7 +226,7 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
if (!desperate && inftl->numfreeEUNs < 2) {
DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free "
"EUNs (%d)\n", inftl->numfreeEUNs);
- return 0xffff;
+ return BLOCK_NIL;
}
/* Scan for a free block */
@@ -281,7 +281,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
silly = MAX_LOOPS;
while (thisEUN < inftl->nb_blocks) {
for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) {
- if ((BlockMap[block] != 0xffff) || BlockDeleted[block])
+ if ((BlockMap[block] != BLOCK_NIL) ||
+ BlockDeleted[block])
continue;
if (inftl_read_oob(mtd, (thisEUN * inftl->EraseSize)
@@ -525,7 +526,7 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
if (!silly--) {
printk(KERN_WARNING "INFTL: infinite loop in "
"Virtual Unit Chain 0x%x\n", thisVUC);
- return 0xffff;
+ return BLOCK_NIL;
}
/* Skip to next block in chain */
@@ -549,7 +550,7 @@ hitused:
* waiting to be picked up. We're going to have to fold
* a chain to make room.
*/
- thisEUN = INFTL_makefreeblock(inftl, 0xffff);
+ thisEUN = INFTL_makefreeblock(inftl, BLOCK_NIL);
/*
* Hopefully we free something, lets try again.
@@ -631,7 +632,7 @@ hitused:
printk(KERN_WARNING "INFTL: error folding to make room for Virtual "
"Unit Chain 0x%x\n", thisVUC);
- return 0xffff;
+ return BLOCK_NIL;
}
/*
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c
index b08a798ee25..2aac41bde8b 100644
--- a/drivers/mtd/maps/integrator-flash.c
+++ b/drivers/mtd/maps/integrator-flash.c
@@ -42,10 +42,8 @@
#include <mach/hardware.h>
#include <asm/system.h>
-#define SUBDEV_NAME_SIZE (BUS_ID_SIZE + 2)
-
struct armflash_subdev_info {
- char name[SUBDEV_NAME_SIZE];
+ char *name;
struct mtd_info *mtd;
struct map_info map;
struct flash_platform_data *plat;
@@ -134,6 +132,8 @@ static void armflash_subdev_remove(struct armflash_subdev_info *subdev)
map_destroy(subdev->mtd);
if (subdev->map.virt)
iounmap(subdev->map.virt);
+ kfree(subdev->name);
+ subdev->name = NULL;
release_mem_region(subdev->map.phys, subdev->map.size);
}
@@ -177,16 +177,22 @@ static int armflash_probe(struct platform_device *dev)
if (nr == 1)
/* No MTD concatenation, just use the default name */
- snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s",
- dev_name(&dev->dev));
+ subdev->name = kstrdup(dev_name(&dev->dev), GFP_KERNEL);
else
- snprintf(subdev->name, SUBDEV_NAME_SIZE, "%s-%d",
- dev_name(&dev->dev), i);
+ subdev->name = kasprintf(GFP_KERNEL, "%s-%d",
+ dev_name(&dev->dev), i);
+ if (!subdev->name) {
+ err = -ENOMEM;
+ break;
+ }
subdev->plat = plat;
err = armflash_subdev_probe(subdev, res);
- if (err)
+ if (err) {
+ kfree(subdev->name);
+ subdev->name = NULL;
break;
+ }
}
info->nr_subdev = i;
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 2802992b39d..20c828ba940 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -534,7 +534,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
&num_partitions);
if ((!partitions) || (num_partitions == 0)) {
- printk(KERN_ERR "atmel_nand: No parititions defined, or unsupported device.\n");
+ printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n");
res = ENXIO;
goto err_no_partitions;
}
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 0cd76f89f4b..ebd07e95b81 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -11,6 +11,8 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
@@ -541,7 +543,7 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
unsigned long timeo = jiffies;
- int status, state = this->state;
+ int status = NAND_STATUS_FAIL, state = this->state;
if (state == FL_ERASING)
timeo += (HZ * 400) / 1000;
@@ -556,8 +558,9 @@ static int omap_wait(struct mtd_info *mtd, struct nand_chip *chip)
while (time_before(jiffies, timeo)) {
status = __raw_readb(this->IO_ADDR_R);
- if (!(status & 0x40))
+ if (status & NAND_STATUS_READY)
break;
+ cond_resched();
}
return status;
}
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index e3f8495a94c..fb86cacd5bd 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -208,7 +208,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
/* Normally, we force a fold to happen before we run out of free blocks completely */
if (!desperate && nftl->numfreeEUNs < 2) {
DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
- return 0xffff;
+ return BLOCK_NIL;
}
/* Scan for a free block */
@@ -230,11 +230,11 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
printk("Argh! No free blocks found! LastFreeEUN = %d, "
"FirstEUN = %d\n", nftl->LastFreeEUN,
le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
- return 0xffff;
+ return BLOCK_NIL;
}
} while (pot != nftl->LastFreeEUN);
- return 0xffff;
+ return BLOCK_NIL;
}
static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
@@ -431,7 +431,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
/* add the header so that it is now a valid chain */
oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
- oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
+ oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = BLOCK_NIL;
nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
8, &retlen, (char *)&oob.u);
@@ -515,7 +515,7 @@ static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
if (ChainLength < 2) {
printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
"Failing request\n");
- return 0xffff;
+ return BLOCK_NIL;
}
return NFTL_foldchain (nftl, LongestChain, pendingblock);
@@ -578,7 +578,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
printk(KERN_WARNING
"Infinite loop in Virtual Unit Chain 0x%x\n",
thisVUC);
- return 0xffff;
+ return BLOCK_NIL;
}
/* Skip to next block in chain */
@@ -601,7 +601,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
//u16 startEUN = nftl->EUNtable[thisVUC];
//printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
- writeEUN = NFTL_makefreeblock(nftl, 0xffff);
+ writeEUN = NFTL_makefreeblock(nftl, BLOCK_NIL);
if (writeEUN == BLOCK_NIL) {
/* OK, we accept that the above comment is
@@ -673,7 +673,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
thisVUC);
- return 0xffff;
+ return BLOCK_NIL;
}
static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 367bec63620..e29fb1a4a61 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -485,7 +485,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (el_debug > 2)
pr_debug(" queued xmit.\n");
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* A receive upset our load, despite our best efforts */
if (el_debug > 2)
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index f71b3540275..7bba480d722 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1101,7 +1101,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
prime_rx(dev);
spin_unlock_irqrestore(&adapter->lock, flags);
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/******************************************************
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 96b86659381..9e93a0b39b6 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -537,7 +537,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
/* You might need to clean up and record Tx statistics here. */
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index d2137efbd45..d2515d840c0 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -892,7 +892,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 4a7c32895be..3116410b349 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -1056,7 +1056,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
netif_wake_queue(dev);
}
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
@@ -1119,7 +1119,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index cdd955c4014..70c701b80d9 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -1198,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
netif_wake_queue(dev);
dev_kfree_skb(skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index aaa8a9f405d..72b9ed7f464 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1035,7 +1035,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
atomic_dec(&lp->tx_count);
@@ -1066,7 +1066,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
p->control &= ~CONTROL_EOL;
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index c34aee91250..202048450ee 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -2083,7 +2083,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
iowrite8(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
- return 0;
+ return NETDEV_TX_OK;
}
static int
@@ -2173,7 +2173,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
iowrite16(DownUnstall, ioaddr + EL3_CMD);
spin_unlock_irqrestore(&vp->lock, flags);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 69f5b7d298a..b1e5764628c 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -585,7 +585,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
lp->tx_full = 1;
spin_unlock_irqrestore (&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
EXPORT_SYMBOL_GPL(lance_start_xmit);
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 50efde11ea6..07919d0877e 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -891,7 +891,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
cpw8(TxPoll, NormalTxPoll);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 0e2ba21d444..b39ec98345e 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1707,7 +1707,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
} else {
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&tp->lock, flags);
@@ -1732,7 +1732,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
pr_debug("%s: Queued Tx packet size %u to slot %d.\n",
dev->name, len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 77547545509..996cc910221 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -1068,7 +1068,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
netif_stop_queue(dev);
@@ -1110,7 +1110,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void print_eth(unsigned char *add, char *str)
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 85a18175730..7302e4385bc 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -553,11 +553,11 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
volatile struct lance_regs *ll = lp->ll;
volatile struct lance_init_block *ib = lp->init_block;
int entry, skblen;
- int status = 0;
+ int status = NETDEV_TX_OK;
unsigned long flags;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
skblen = max_t(unsigned, skb->len, ETH_ZLEN);
local_irq_save(flags);
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 19831bd6401..61ac671f97b 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1346,7 +1346,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
This function returns all the memory mapped registers of the device.
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 7f832541980..29b279f88ef 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -920,7 +920,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 78cea5e80b1..6cfd961bb8d 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -132,7 +132,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
}
if(rt == NULL) {
spin_unlock(&ipddp_route_lock);
- return 0;
+ return NETDEV_TX_OK;
}
our_addr = atalk_find_dev_addr(rt->dev);
@@ -181,7 +181,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&ipddp_route_lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index b642647170b..c80fb9cf8ff 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -932,7 +932,7 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* initialization stuff */
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 58e8d522e5b..47d976cc3d7 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -610,7 +610,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -685,7 +685,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
local_irq_restore(flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 627bc75da17..164b37e85ee 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -482,7 +482,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 5041d10bae9..c8bc60a7040 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -834,7 +834,7 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
we free and return(0) or don't free and return 1 */
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index edf770f639f..e47c0d96285 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -748,7 +748,7 @@ ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
out:
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 455037134aa..1f7a69c929a 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -511,7 +511,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
priv(dev)->stats.tx_dropped ++;
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
length = (length + 1) & ~1;
@@ -562,7 +562,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
out:
- return 0;
+ return NETDEV_TX_OK;
}
static irqreturn_t
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index cf30e278f18..5349c58d1fa 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -643,7 +643,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev)
netif_start_queue (dev);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 5425ab0c38c..0c0deceb693 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -796,7 +796,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
if (len > skb->len) {
if (skb_padto(skb, len))
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue (dev);
@@ -846,7 +846,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
lp->tx_full = 1;
spin_unlock_irqrestore (&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 4317b3edb3d..4beacc9c909 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -587,7 +587,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index d3c734f4d67..2aab1ebc6cd 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -988,7 +988,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 36d4d377ec2..1f7f015442d 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1756,15 +1756,15 @@ static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *inf
struct b44 *bp = netdev_priv(dev);
struct ssb_bus *bus = bp->sdev->bus;
- strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
- strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver));
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
switch (bus->bustype) {
case SSB_BUSTYPE_PCI:
- strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
+ strlcpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
break;
case SSB_BUSTYPE_PCMCIA:
case SSB_BUSTYPE_SSB:
- strncpy(info->bus_info, "SSB", sizeof(info->bus_info));
+ strlcpy(info->bus_info, "SSB", sizeof(info->bus_info));
break;
}
}
diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig
index c6934f179c0..fdb6e81a437 100644
--- a/drivers/net/benet/Kconfig
+++ b/drivers/net/benet/Kconfig
@@ -1,7 +1,6 @@
config BE2NET
tristate "ServerEngines' 10Gbps NIC - BladeEngine 2"
depends on PCI && INET
- select INET_LRO
help
This driver implements the NIC functionality for ServerEngines'
10Gbps network adapter - BladeEngine 2.
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 5b4bf3d2cdc..41cddbedbf2 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -28,11 +28,10 @@
#include <linux/if_vlan.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
-#include <linux/inet_lro.h>
#include "be_hw.h"
-#define DRV_VER "2.0.348"
+#define DRV_VER "2.0.400"
#define DRV_NAME "be2net"
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
#define OC_NAME "Emulex OneConnect 10Gbps NIC"
@@ -72,9 +71,6 @@ static inline char *nic_name(struct pci_dev *pdev)
#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
#define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST)
-#define BE_MAX_LRO_DESCRIPTORS 16
-#define BE_MAX_FRAGS_PER_FRAME (min((u32) 16, (u32) MAX_SKB_FRAGS))
-
struct be_dma_mem {
void *va;
dma_addr_t dma;
@@ -189,8 +185,6 @@ struct be_drvr_stats {
u32 be_polls; /* number of times NAPI called poll function */
u32 be_rx_events; /* number of ucast rx completion events */
u32 be_rx_compl; /* number of rx completion entries processed */
- u32 be_lro_hgram_data[8]; /* histogram of LRO data packets */
- u32 be_lro_hgram_ack[8]; /* histogram of LRO ACKs */
ulong be_rx_jiffies;
u64 be_rx_bytes;
u64 be_rx_bytes_prev;
@@ -233,8 +227,6 @@ struct be_rx_obj {
struct be_queue_info q;
struct be_queue_info cq;
struct be_rx_page_info page_info_tbl[RX_Q_LEN];
- struct net_lro_mgr lro_mgr;
- struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS];
};
#define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */
@@ -271,7 +263,6 @@ struct be_adapter {
/* Ethtool knobs and info */
bool rx_csum; /* BE card must perform rx-checksumming */
- u32 max_rx_coal;
char fw_ver[FW_VER_LEN];
u32 if_handle; /* Used to configure filtering */
u32 pmac_id; /* MAC addr handle used by BE card */
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index cccc5419ad7..f3f0f91e38c 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -127,8 +127,6 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
- coalesce->rx_max_coalesced_frames = adapter->max_rx_coal;
-
coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd;
coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd;
@@ -144,8 +142,7 @@ be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
}
/*
- * This routine is used to set interrup coalescing delay *as well as*
- * the number of pkts to coalesce for LRO.
+ * This routine is used to set interrup coalescing delay
*/
static int
be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
@@ -161,10 +158,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
if (coalesce->use_adaptive_tx_coalesce == 1)
return -EINVAL;
- adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
- if (adapter->max_rx_coal > BE_MAX_FRAGS_PER_FRAME)
- adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
-
/* if AIC is being turned on now, start with an EQD of 0 */
if (rx_eq->enable_aic == 0 &&
coalesce->use_adaptive_rx_coalesce == 1) {
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index dea3155688b..c56487e3700 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -742,7 +742,7 @@ done:
return;
}
-/* Process the RX completion indicated by rxcp when LRO is disabled */
+/* Process the RX completion indicated by rxcp when GRO is disabled */
static void be_rx_compl_process(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
@@ -789,13 +789,14 @@ static void be_rx_compl_process(struct be_adapter *adapter,
return;
}
-/* Process the RX completion indicated by rxcp when LRO is enabled */
-static void be_rx_compl_process_lro(struct be_adapter *adapter,
+/* Process the RX completion indicated by rxcp when GRO is enabled */
+static void be_rx_compl_process_gro(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
struct be_rx_page_info *page_info;
- struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
+ struct sk_buff *skb = NULL;
struct be_queue_info *rxq = &adapter->rx_obj.q;
+ struct be_eq_obj *eq_obj = &adapter->rx_eq;
u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
u16 i, rxq_idx = 0, vid, j;
@@ -804,6 +805,12 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+ skb = napi_get_frags(&eq_obj->napi);
+ if (!skb) {
+ be_rx_compl_discard(adapter, rxcp);
+ return;
+ }
+
remaining = pkt_size;
for (i = 0, j = -1; i < num_rcvd; i++) {
page_info = get_rx_page_info(adapter, rxq_idx);
@@ -814,13 +821,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
if (i == 0 || page_info->page_offset == 0) {
/* First frag or Fresh page */
j++;
- rx_frags[j].page = page_info->page;
- rx_frags[j].page_offset = page_info->page_offset;
- rx_frags[j].size = 0;
+ skb_shinfo(skb)->frags[j].page = page_info->page;
+ skb_shinfo(skb)->frags[j].page_offset =
+ page_info->page_offset;
+ skb_shinfo(skb)->frags[j].size = 0;
} else {
put_page(page_info->page);
}
- rx_frags[j].size += curr_frag_len;
+ skb_shinfo(skb)->frags[j].size += curr_frag_len;
remaining -= curr_frag_len;
index_inc(&rxq_idx, rxq->len);
@@ -828,9 +836,14 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
}
BUG_ON(j > MAX_SKB_FRAGS);
+ skb_shinfo(skb)->nr_frags = j + 1;
+ skb->len = pkt_size;
+ skb->data_len = pkt_size;
+ skb->truesize += pkt_size;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
if (likely(!vlanf)) {
- lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size,
- pkt_size, NULL, 0);
+ napi_gro_frags(&eq_obj->napi);
} else {
vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
vid = be16_to_cpu(vid);
@@ -838,9 +851,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter,
if (!adapter->vlan_grp || adapter->num_vlans == 0)
return;
- lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr,
- rx_frags, pkt_size, pkt_size, adapter->vlan_grp,
- vid, NULL, 0);
+ vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid);
}
be_rx_stats_update(adapter, pkt_size, num_rcvd);
@@ -1183,7 +1194,6 @@ static int be_rx_queues_create(struct be_adapter *adapter)
struct be_queue_info *eq, *q, *cq;
int rc;
- adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
adapter->rx_eq.max_eqd = BE_MAX_EQD;
adapter->rx_eq.min_eqd = 0;
@@ -1305,7 +1315,7 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
return IRQ_HANDLED;
}
-static inline bool do_lro(struct be_adapter *adapter,
+static inline bool do_gro(struct be_adapter *adapter,
struct be_eth_rx_compl *rxcp)
{
int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
@@ -1314,8 +1324,7 @@ static inline bool do_lro(struct be_adapter *adapter,
if (err)
drvr_stats(adapter)->be_rxcp_err++;
- return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ?
- false : true;
+ return (tcp_frame && !err) ? true : false;
}
int be_poll_rx(struct napi_struct *napi, int budget)
@@ -1332,16 +1341,14 @@ int be_poll_rx(struct napi_struct *napi, int budget)
if (!rxcp)
break;
- if (do_lro(adapter, rxcp))
- be_rx_compl_process_lro(adapter, rxcp);
+ if (do_gro(adapter, rxcp))
+ be_rx_compl_process_gro(adapter, rxcp);
else
be_rx_compl_process(adapter, rxcp);
be_rx_compl_reset(rxcp);
}
- lro_flush_all(&adapter->rx_obj.lro_mgr);
-
/* Refill the queue */
if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM)
be_post_rx_frags(adapter);
@@ -1656,57 +1663,6 @@ static int be_close(struct net_device *netdev)
return 0;
}
-static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
- void **ip_hdr, void **tcpudp_hdr,
- u64 *hdr_flags, void *priv)
-{
- struct ethhdr *eh;
- struct vlan_ethhdr *veh;
- struct iphdr *iph;
- u8 *va = page_address(frag->page) + frag->page_offset;
- unsigned long ll_hlen;
-
- prefetch(va);
- eh = (struct ethhdr *)va;
- *mac_hdr = eh;
- ll_hlen = ETH_HLEN;
- if (eh->h_proto != htons(ETH_P_IP)) {
- if (eh->h_proto == htons(ETH_P_8021Q)) {
- veh = (struct vlan_ethhdr *)va;
- if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
- return -1;
-
- ll_hlen += VLAN_HLEN;
- } else {
- return -1;
- }
- }
- *hdr_flags = LRO_IPV4;
- iph = (struct iphdr *)(va + ll_hlen);
- *ip_hdr = iph;
- if (iph->protocol != IPPROTO_TCP)
- return -1;
- *hdr_flags |= LRO_TCP;
- *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
-
- return 0;
-}
-
-static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev)
-{
- struct net_lro_mgr *lro_mgr;
-
- lro_mgr = &adapter->rx_obj.lro_mgr;
- lro_mgr->dev = netdev;
- lro_mgr->features = LRO_F_NAPI;
- lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
- lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
- lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS;
- lro_mgr->lro_arr = adapter->rx_obj.lro_desc;
- lro_mgr->get_frag_header = be_get_frag_header;
- lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME;
-}
-
static struct net_device_ops be_netdev_ops = {
.ndo_open = be_open,
.ndo_stop = be_close,
@@ -1727,7 +1683,7 @@ static void be_netdev_init(struct net_device *netdev)
netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM;
+ NETIF_F_IPV6_CSUM | NETIF_F_GRO;
netdev->flags |= IFF_MULTICAST;
@@ -1737,8 +1693,6 @@ static void be_netdev_init(struct net_device *netdev)
SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
- be_lro_init(adapter, netdev);
-
netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
BE_NAPI_WEIGHT);
netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index c15fc281f79..f580b21eabd 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -656,7 +656,7 @@ out:
dev->trans_start = jiffies;
dev->stats.tx_packets++;
dev->stats.tx_bytes += (skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
static void bfin_mac_rx(struct net_device *dev)
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 9578a3dfac0..41600011cfd 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1488,7 +1488,7 @@ bmac_output(struct sk_buff *skb, struct net_device *dev)
struct bmac_data *bp = netdev_priv(dev);
skb_queue_tail(bp->queue, skb);
bmac_start(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void bmac_tx_timeout(unsigned long data)
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index b70cc99962f..cec1b1746ae 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -8023,6 +8023,13 @@ static const struct net_device_ops bnx2_netdev_ops = {
#endif
};
+static void inline vlan_features_add(struct net_device *dev, unsigned long flags)
+{
+#ifdef BCM_VLAN
+ dev->vlan_features |= flags;
+#endif
+}
+
static int __devinit
bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -8064,16 +8071,20 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
memcpy(dev->perm_addr, bp->mac_addr, 6);
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ vlan_features_add(dev, NETIF_F_IP_CSUM | NETIF_F_SG);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
dev->features |= NETIF_F_IPV6_CSUM;
-
+ vlan_features_add(dev, NETIF_F_IPV6_CSUM);
+ }
#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
dev->features |= NETIF_F_TSO6;
-
+ vlan_features_add(dev, NETIF_F_TSO6);
+ }
if ((rc = register_netdev(dev))) {
dev_err(&pdev->dev, "Cannot register net device\n");
goto error;
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 85a737c5c23..8bd80fca978 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -160,7 +160,7 @@ struct sw_rx_page {
#define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT)
#define SGE_PAGE_SIZE PAGE_SIZE
#define SGE_PAGE_SHIFT PAGE_SHIFT
-#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))addr)
+#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))(addr))
/* SGE ring related macros */
#define NUM_RX_SGE_PAGES 2
@@ -1006,6 +1006,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port);
int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port);
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command);
static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
int wait)
diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h
index 03c62421d99..7de83c4a557 100644
--- a/drivers/net/bnx2x_hsi.h
+++ b/drivers/net/bnx2x_hsi.h
@@ -91,6 +91,21 @@ struct shared_hw_cfg { /* NVRAM Offset */
#define SHARED_HW_CFG_HIDE_PORT1 0x00002000
+ /* The fan failure mechanism is usually related to the PHY type
+ since the power consumption of the board is determined by the PHY.
+ Currently, fan is required for most designs with SFX7101, BCM8727
+ and BCM8481. If a fan is not required for a board which uses one
+ of those PHYs, this field should be set to "Disabled". If a fan is
+ required for a different PHY type, this option should be set to
+ "Enabled".
+ The fan failure indication is expected on
+ SPIO5 */
+#define SHARED_HW_CFG_FAN_FAILURE_MASK 0x00180000
+#define SHARED_HW_CFG_FAN_FAILURE_SHIFT 19
+#define SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE 0x00000000
+#define SHARED_HW_CFG_FAN_FAILURE_DISABLED 0x00080000
+#define SHARED_HW_CFG_FAN_FAILURE_ENABLED 0x00100000
+
u32 power_dissipated; /* 0x11c */
#define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000
#define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT 24
@@ -233,6 +248,8 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726 0x00000600
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 0x00000900
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC 0x00000a00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00
#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00
@@ -343,10 +360,16 @@ struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */
#define PORT_FEATURE_MBA_ENABLED 0x02000000
#define PORT_FEATURE_MFW_ENABLED 0x04000000
- /* Check the optic vendor via i2c before allowing it to be used by
- SW */
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLED 0x00000000
-#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED 0x08000000
+ /* Reserved bits: 28-29 */
+ /* Check the optic vendor via i2c against a list of approved modules
+ in a separate nvram image */
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK 0xE0000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_SHIFT 29
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT 0x00000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER 0x20000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG 0x40000000
+#define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN 0x60000000
+
u32 wol_config;
/* Default is used when driver sets to "auto" mode */
@@ -642,6 +665,12 @@ struct drv_func_mb {
#define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000
#define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000
#define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000
+ /*
+ * The optic module verification commands requris bootcode
+ * v5.0.6 or later
+ */
+#define DRV_MSG_CODE_VRFY_OPT_MDL 0xa0000000
+#define REQ_BC_VER_4_VRFY_OPT_MDL 0x00050006
#define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000
#define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000
@@ -676,6 +705,9 @@ struct drv_func_mb {
#define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x90220000
#define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x90230000
#define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x90240000
+#define FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS 0xa0100000
+#define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG 0xa0200000
+#define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED 0xa0300000
#define FW_MSG_CODE_LIC_CHALLENGE 0xff010000
#define FW_MSG_CODE_LIC_RESPONSE 0xff020000
diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c
index 2ee581a2cde..1f17334c8f0 100644
--- a/drivers/net/bnx2x_link.c
+++ b/drivers/net/bnx2x_link.c
@@ -139,21 +139,26 @@
#define SFP_EEPROM_CON_TYPE_VAL_LC 0x7
#define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21
+
+#define SFP_EEPROM_COMP_CODE_ADDR 0x3
+ #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4)
+ #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5)
+ #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6)
+
#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8
#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4
#define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8
-#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
-#define SFP_EEPROM_VENDOR_NAME_SIZE 16
+
#define SFP_EEPROM_OPTIONS_ADDR 0x40
#define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1
#define SFP_EEPROM_OPTIONS_SIZE 2
-#define SFP_MODULE_TYPE_UNKNOWN 0x0
-#define SFP_MODULE_TYPE_LC 0x1
-#define SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE 0x2
-#define SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE 0x3
+#define EDC_MODE_LINEAR 0x0022
+#define EDC_MODE_LIMITING 0x0044
+#define EDC_MODE_PASSIVE_DAC 0x0055
+
+
-#define SFP_LIMITING_MODE_VALUE 0x0044
/**********************************************************/
/* INTERFACE */
/**********************************************************/
@@ -793,6 +798,7 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, u32 ext_phy_type, u8 port)
switch (ext_phy_type) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
/* All MDC/MDIO is directed through single EMAC */
if (REG_RD(bp, NIG_REG_PORT_SWAP))
emac_base = GRCBASE_EMAC0;
@@ -1887,6 +1893,10 @@ static void bnx2x_ext_phy_reset(struct link_params *params,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_CTRL, 0xa040);
break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* Restore normal power mode*/
@@ -2171,13 +2181,15 @@ static u8 bnx2x_bcm8073_xaui_wa(struct link_params *params)
}
-static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr, u32 shmem_base)
+static void bnx2x_bcm8073_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 ext_phy_type,
+ u32 shmem_base)
{
/* Boot port from external ROM */
/* EDC grst */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2185,21 +2197,21 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* ucode reboot and rst */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
0x008c);
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0001);
/* Reset internal microprocessor */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2207,7 +2219,7 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* Release srst bit */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL,
@@ -2218,17 +2230,36 @@ static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
/* Clear ser_boot_ctl bit */
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_MISC_CTRL1, 0x0000);
bnx2x_save_bcm_spirom_ver(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ ext_phy_type,
ext_phy_addr,
shmem_base);
}
+static void bnx2x_bcm8073_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 shmem_base)
+{
+ bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
+ shmem_base);
+}
+
+static void bnx2x_bcm8727_external_rom_boot(struct bnx2x *bp, u8 port,
+ u8 ext_phy_addr,
+ u32 shmem_base)
+{
+ bnx2x_bcm8073_bcm8727_external_rom_boot(bp, port, ext_phy_addr,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ shmem_base);
+
+}
+
static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
{
struct bnx2x *bp = params->bp;
@@ -2258,9 +2289,10 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
MDIO_PMA_REG_GEN_CTRL,
MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
+ /* Set PLL register value to be same like in P13 ver */
bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_GEN_CTRL2,
+ MDIO_PMA_REG_PLL_CTRL,
0x73A0);
/* Clear soft reset.
@@ -2285,15 +2317,16 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
params->shmem_base);
}
-static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
- u8 ext_phy_addr, u8 tx_en)
+static void bnx2x_sfp_set_transmitter(struct bnx2x *bp, u8 port,
+ u32 ext_phy_type, u8 ext_phy_addr,
+ u8 tx_en)
{
u16 val;
DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x\n",
tx_en, port);
/* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/
bnx2x_cl45_read(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
@@ -2305,18 +2338,19 @@ static void bnx2x_bcm8726_set_transmitter(struct bnx2x *bp, u8 port,
val |= (1<<15);
bnx2x_cl45_write(bp, port,
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+ ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_PHY_IDENTIFIER,
val);
}
-
-static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
- u8 byte_cnt, u8 *o_buf) {
+static u8 bnx2x_8726_read_sfp_module_eeprom(struct link_params *params,
+ u16 addr, u8 byte_cnt, u8 *o_buf)
+{
struct bnx2x *bp = params->bp;
- u16 val, i;
+ u16 val = 0;
+ u16 i;
u8 port = params->port;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
@@ -2332,7 +2366,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT,
+ MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
(byte_cnt | 0xa000));
/* Set the read command address */
@@ -2340,7 +2374,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR,
+ MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
addr);
/* Activate read command */
@@ -2348,7 +2382,7 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
0x2c0f);
/* Wait up to 500us for command complete status */
@@ -2357,18 +2391,18 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE)
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
break;
udelay(5);
}
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) !=
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE) {
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
DP(NETIF_MSG_LINK,
"Got bad status 0x%x when reading from SFP+ EEPROM\n",
- (val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK));
+ (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
return -EINVAL;
}
@@ -2387,29 +2421,147 @@ static u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
ext_phy_type,
ext_phy_addr,
MDIO_PMA_DEVAD,
- MDIO_PMA_REG_8726_TWO_WIRE_CTRL, &val);
- if ((val & MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK) ==
- MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE)
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
return 0;;
msleep(1);
}
return -EINVAL;
}
+static u8 bnx2x_8727_read_sfp_module_eeprom(struct link_params *params,
+ u16 addr, u8 byte_cnt, u8 *o_buf)
+{
+ struct bnx2x *bp = params->bp;
+ u16 val, i;
+ u8 port = params->port;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+ if (byte_cnt > 16) {
+ DP(NETIF_MSG_LINK, "Reading from eeprom is"
+ " is limited to 0xf\n");
+ return -EINVAL;
+ }
+
+ /* Need to read from 1.8000 to clear it */
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+ &val);
-static u8 bnx2x_get_sfp_module_type(struct link_params *params,
- u8 *module_type)
+ /* Set the read command byte count */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT,
+ ((byte_cnt < 2) ? 2 : byte_cnt));
+
+ /* Set the read command address */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR,
+ addr);
+ /* Set the destination address */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ 0x8004,
+ MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF);
+
+ /* Activate read command */
+ bnx2x_cl45_write(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL,
+ 0x8002);
+ /* Wait appropriate time for two-wire command to finish before
+ polling the status register */
+ msleep(1);
+
+ /* Wait up to 500us for command complete status */
+ for (i = 0; i < 100; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE)
+ break;
+ udelay(5);
+ }
+
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) !=
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) {
+ DP(NETIF_MSG_LINK,
+ "Got bad status 0x%x when reading from SFP+ EEPROM\n",
+ (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK));
+ return -EINVAL;
+ }
+
+ /* Read the buffer */
+ for (i = 0; i < byte_cnt; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val);
+ o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK);
+ }
+
+ for (i = 0; i < 100; i++) {
+ bnx2x_cl45_read(bp, port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val);
+ if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) ==
+ MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE)
+ return 0;;
+ msleep(1);
+ }
+
+ return -EINVAL;
+}
+
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+ u8 byte_cnt, u8 *o_buf)
+{
+ u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+ return bnx2x_8726_read_sfp_module_eeprom(params, addr,
+ byte_cnt, o_buf);
+ else if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+ return bnx2x_8727_read_sfp_module_eeprom(params, addr,
+ byte_cnt, o_buf);
+ return -EINVAL;
+}
+
+static u8 bnx2x_get_edc_mode(struct link_params *params,
+ u16 *edc_mode)
{
struct bnx2x *bp = params->bp;
- u8 val;
- *module_type = SFP_MODULE_TYPE_UNKNOWN;
+ u8 val, check_limiting_mode = 0;
+ *edc_mode = EDC_MODE_LIMITING;
/* First check for copper cable */
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_CON_TYPE_ADDR,
1,
&val) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM");
+ DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n");
return -EINVAL;
}
@@ -2433,13 +2585,13 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) {
DP(NETIF_MSG_LINK, "Active Copper cable detected\n");
- *module_type = SFP_MODULE_TYPE_ACTIVE_COPPER_CABLE;
+ check_limiting_mode = 1;
} else if (copper_module_type &
SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) {
DP(NETIF_MSG_LINK, "Passive Copper"
" cable detected\n");
- *module_type =
- SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE;
+ *edc_mode =
+ EDC_MODE_PASSIVE_DAC;
} else {
DP(NETIF_MSG_LINK, "Unknown copper-cable-"
"type 0x%x !!!\n", copper_module_type);
@@ -2449,7 +2601,7 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
}
case SFP_EEPROM_CON_TYPE_VAL_LC:
DP(NETIF_MSG_LINK, "Optic module detected\n");
- *module_type = SFP_MODULE_TYPE_LC;
+ check_limiting_mode = 1;
break;
default:
@@ -2457,89 +2609,92 @@ static u8 bnx2x_get_sfp_module_type(struct link_params *params,
val);
return -EINVAL;
}
+
+ if (check_limiting_mode) {
+ u8 options[SFP_EEPROM_OPTIONS_SIZE];
+ if (bnx2x_read_sfp_module_eeprom(params,
+ SFP_EEPROM_OPTIONS_ADDR,
+ SFP_EEPROM_OPTIONS_SIZE,
+ options) != 0) {
+ DP(NETIF_MSG_LINK, "Failed to read Option"
+ " field from module EEPROM\n");
+ return -EINVAL;
+ }
+ if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK))
+ *edc_mode = EDC_MODE_LINEAR;
+ else
+ *edc_mode = EDC_MODE_LIMITING;
+ }
+ DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode);
return 0;
}
-
/* This function read the relevant field from the module ( SFP+ ),
and verify it is compliant with this board */
-static u8 bnx2x_verify_sfp_module(struct link_params *params,
- u8 module_type)
+static u8 bnx2x_verify_sfp_module(struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u8 *str_p, *tmp_buf;
- u16 i;
-
-#define COMPLIANCE_STR_CNT 6
- u8 *compliance_str[] = {"Broadcom", "JDSU", "Molex Inc", "PICOLIGHT",
- "FINISAR CORP. ", "Amphenol"};
- u8 buf[SFP_EEPROM_VENDOR_NAME_SIZE];
- /* Passive Copper cables are allowed to participate,
- since the module is hardwired to the copper cable */
-
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
+ u32 val;
+ u32 fw_resp;
+ char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1];
+ char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1];
+
+ val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].config));
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) {
DP(NETIF_MSG_LINK, "NOT enforcing module verification\n");
return 0;
}
- if (module_type != SFP_MODULE_TYPE_LC) {
- DP(NETIF_MSG_LINK, "No need to verify copper cable\n");
+ /* Ask the FW to validate the module */
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY)) {
+ DP(NETIF_MSG_LINK, "FW does not support OPT MDL "
+ "verification\n");
+ return -EINVAL;
+ }
+
+ fw_resp = bnx2x_fw_command(bp, DRV_MSG_CODE_VRFY_OPT_MDL);
+ if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) {
+ DP(NETIF_MSG_LINK, "Approved module\n");
return 0;
}
- /* In case of non copper cable or Active copper cable,
- verify that the SFP+ module is compliant with this board*/
+ /* format the warning message */
if (bnx2x_read_sfp_module_eeprom(params,
SFP_EEPROM_VENDOR_NAME_ADDR,
SFP_EEPROM_VENDOR_NAME_SIZE,
- buf) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read Vendor-Name from"
- " module EEPROM\n");
- return -EINVAL;
- }
- for (i = 0; i < COMPLIANCE_STR_CNT; i++) {
- str_p = compliance_str[i];
- tmp_buf = buf;
- while (*str_p) {
- if ((u8)(*tmp_buf) != (u8)(*str_p))
- break;
- str_p++;
- tmp_buf++;
- }
+ (u8 *)vendor_name))
+ vendor_name[0] = '\0';
+ else
+ vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0';
+ if (bnx2x_read_sfp_module_eeprom(params,
+ SFP_EEPROM_PART_NO_ADDR,
+ SFP_EEPROM_PART_NO_SIZE,
+ (u8 *)vendor_pn))
+ vendor_pn[0] = '\0';
+ else
+ vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0';
- if (!(*str_p)) {
- DP(NETIF_MSG_LINK, "SFP+ Module verified, "
- "index=%x\n", i);
- return 0;
- }
- }
- DP(NETIF_MSG_LINK, "Incompliant SFP+ module. Disable module !!!\n");
+ printk(KERN_INFO PFX "Warning: "
+ "Unqualified SFP+ module "
+ "detected on %s, Port %d from %s part number %s\n"
+ , bp->dev->name, params->port,
+ vendor_name, vendor_pn);
return -EINVAL;
}
-
static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
- u8 module_type)
+ u16 edc_mode)
{
struct bnx2x *bp = params->bp;
u8 port = params->port;
- u8 options[SFP_EEPROM_OPTIONS_SIZE];
- u8 limiting_mode;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u16 cur_limiting_mode;
- if (bnx2x_read_sfp_module_eeprom(params,
- SFP_EEPROM_OPTIONS_ADDR,
- SFP_EEPROM_OPTIONS_SIZE,
- options) != 0) {
- DP(NETIF_MSG_LINK, "Failed to read Option field from"
- " module EEPROM\n");
- return -EINVAL;
- }
- limiting_mode = !(options[0] &
- SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
bnx2x_cl45_read(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
@@ -2550,26 +2705,23 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
cur_limiting_mode);
- if (limiting_mode &&
- (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
+ if (edc_mode == EDC_MODE_LIMITING) {
DP(NETIF_MSG_LINK,
- "Module options = 0x%x.Setting LIMITING MODE\n",
- options[0]);
+ "Setting LIMITING MODE\n");
bnx2x_cl45_write(bp, port,
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_ROM_VER2,
- SFP_LIMITING_MODE_VALUE);
+ EDC_MODE_LIMITING);
} else { /* LRM mode ( default )*/
- DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
- options[0]);
+ DP(NETIF_MSG_LINK, "Setting LRM MODE\n");
/* Changing to LRM mode takes quite few seconds.
So do it only if current mode is limiting
( default is LRM )*/
- if (cur_limiting_mode != SFP_LIMITING_MODE_VALUE)
+ if (cur_limiting_mode != EDC_MODE_LIMITING)
return 0;
bnx2x_cl45_write(bp, port,
@@ -2600,6 +2752,56 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
return 0;
}
+static u8 bnx2x_bcm8727_set_limiting_mode(struct link_params *params,
+ u16 edc_mode)
+{
+ struct bnx2x *bp = params->bp;
+ u8 port = params->port;
+ u16 phy_identifier;
+ u16 rom_ver2_val;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &phy_identifier);
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ (phy_identifier & ~(1<<9)));
+
+ bnx2x_cl45_read(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER2,
+ &rom_ver2_val);
+ /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER2,
+ (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff));
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ (phy_identifier | (1<<9)));
+
+ return 0;
+}
+
+
static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
{
u8 val;
@@ -2619,61 +2821,114 @@ static u8 bnx2x_wait_for_sfp_module_initialized(struct link_params *params)
return -EINVAL;
}
+static void bnx2x_8727_power_module(struct bnx2x *bp,
+ struct link_params *params,
+ u8 ext_phy_addr, u8 is_power_up) {
+ /* Make sure GPIOs are not using for LED mode */
+ u16 val;
+ u8 port = params->port;
+ /*
+ * In the GPIO register, bit 4 is use to detemine if the GPIOs are
+ * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for
+ * output
+ * Bits 0-1 determine the gpios value for OUTPUT in case bit 4 val is 0
+ * Bits 8-9 determine the gpios value for INPUT in case bit 4 val is 1
+ * where the 1st bit is the over-current(only input), and 2nd bit is
+ * for power( only output )
+ */
+
+ /*
+ * In case of NOC feature is disabled and power is up, set GPIO control
+ * as input to enable listening of over-current indication
+ */
+
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BCM8727_NOC) && is_power_up)
+ val = (1<<4);
+ else
+ /*
+ * Set GPIO control to OUTPUT, and set the power bit
+ * to according to the is_power_up
+ */
+ val = ((!(is_power_up)) << 1);
+
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ val);
+}
+
static u8 bnx2x_sfp_module_detection(struct link_params *params)
{
struct bnx2x *bp = params->bp;
- u8 module_type;
+ u16 edc_mode;
+ u8 rc = 0;
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(params->ext_phy_config);
-
- if (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
- DP(NETIF_MSG_LINK, "Module detection is not required "
- "for this phy\n");
- return 0;
- }
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].config));
DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
params->port);
- if (bnx2x_get_sfp_module_type(params,
- &module_type) != 0) {
+ if (bnx2x_get_edc_mode(params, &edc_mode) != 0) {
DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
- if (!(params->feature_config_flags &
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED)) {
- /* In case module detection is disabled, it trys to
- link up. The issue that can happen here is LRM /
- LIMITING mode which set according to the module-type*/
- DP(NETIF_MSG_LINK, "Unable to read module-type."
- "Probably due to Bit Stretching."
- " Proceeding...\n");
- } else {
- return -EINVAL;
- }
- } else if (bnx2x_verify_sfp_module(params, module_type) !=
+ return -EINVAL;
+ } else if (bnx2x_verify_sfp_module(params) !=
0) {
/* check SFP+ module compatibility */
DP(NETIF_MSG_LINK, "Module verification failed!!\n");
+ rc = -EINVAL;
/* Turn on fault module-detected led */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
MISC_REGISTERS_GPIO_HIGH,
params->port);
- return -EINVAL;
+ if ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
+ ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
+ /* Shutdown SFP+ module */
+ DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
+ bnx2x_8727_power_module(bp, params,
+ ext_phy_addr, 0);
+ return rc;
+ }
+ } else {
+ /* Turn off fault module-detected led */
+ DP(NETIF_MSG_LINK, "Turn off fault module-detected led\n");
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
+ MISC_REGISTERS_GPIO_LOW,
+ params->port);
}
- /* Turn off fault module-detected led */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0,
- MISC_REGISTERS_GPIO_LOW,
- params->port);
+ /* power up the SFP module */
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
+ bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
- /* Check and set limiting mode / LRM mode */
- bnx2x_bcm8726_set_limiting_mode(params, module_type);
+ /* Check and set limiting mode / LRM mode on 8726.
+ On 8727 it is done automatically */
+ if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
+ bnx2x_bcm8726_set_limiting_mode(params, edc_mode);
+ else
+ bnx2x_bcm8727_set_limiting_mode(params, edc_mode);
+ /*
+ * Enable transmit for this module if the module is approved, or
+ * if unapproved modules should also enable the Tx laser
+ */
+ if (rc == 0 ||
+ (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) !=
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 1);
+ else
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 0);
- /* Enable transmit for this module */
- bnx2x_bcm8726_set_transmitter(bp, params->port,
- ext_phy_addr, 1);
- return 0;
+ return rc;
}
void bnx2x_handle_module_detect_int(struct link_params *params)
@@ -2696,8 +2951,8 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
port);
- if (bnx2x_wait_for_sfp_module_initialized(params)
- == 0)
+ if (bnx2x_wait_for_sfp_module_initialized(params) ==
+ 0)
bnx2x_sfp_module_detection(params);
else
DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
@@ -2705,13 +2960,22 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
u8 ext_phy_addr = ((params->ext_phy_config &
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 ext_phy_type =
+ XGXS_EXT_PHY_TYPE(params->ext_phy_config);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+
bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
MISC_REGISTERS_GPIO_INT_OUTPUT_SET,
port);
/* Module was plugged out. */
/* Disable transmit for this module */
- bnx2x_bcm8726_set_transmitter(bp, params->port,
- ext_phy_addr, 0);
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ ext_phy_type, ext_phy_addr, 0);
}
}
@@ -3160,6 +3424,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
driver is loaded, it reset all registers, including the
transmitter */
bnx2x_sfp_module_detection(params);
+
+ /* Set Flow control */
+ bnx2x_ext_phy_set_pause(params, vars);
if (params->req_line_speed == SPEED_1000) {
DP(NETIF_MSG_LINK, "Setting 1G force\n");
bnx2x_cl45_write(bp, params->port, ext_phy_type,
@@ -3450,6 +3717,187 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
((val & (1<<7)) > 0));
break;
}
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+ u16 tmp1;
+ u16 rx_alarm_ctrl_val;
+ u16 lasi_ctrl_val;
+
+ /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */
+
+ u16 mod_abs;
+ rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
+ lasi_ctrl_val = 0x0004;
+
+ DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
+ /* enable LASI */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ rx_alarm_ctrl_val);
+
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_LASI_CTRL,
+ lasi_ctrl_val);
+
+ /* Initially configure MOD_ABS to interrupt when
+ module is presence( bit 8) */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+ /* Set EDC off by setting OPTXLOS signal input to low
+ (bit 9).
+ When the EDC is off it locks onto a reference clock and
+ avoids becoming 'lost'.*/
+ mod_abs &= ~((1<<8) | (1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Make MOD_ABS give interrupt on change */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ &val);
+ val |= (1<<12);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ val);
+
+ /* Set 8727 GPIOs to input to allow reading from the
+ 8727 GPIO0 status which reflect SFP+ module
+ over-current */
+
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ &val);
+ val &= 0xff8f; /* Reset bits 4-6 */
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_PCS_OPT_CTRL,
+ val);
+
+ bnx2x_8727_power_module(bp, params, ext_phy_addr, 1);
+ bnx2x_bcm8073_set_xaui_low_power_mode(params);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_M8051_MSGOUT_REG,
+ &tmp1);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &tmp1);
+
+ /* Set option 1G speed */
+ if (params->req_line_speed == SPEED_1000) {
+
+ DP(NETIF_MSG_LINK, "Setting 1G force\n");
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL, 0x40);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, 0xD);
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, &tmp1);
+ DP(NETIF_MSG_LINK, "1.7 = 0x%x \n", tmp1);
+
+ } else if ((params->req_line_speed ==
+ SPEED_AUTO_NEG) &&
+ ((params->speed_cap_mask &
+ PORT_HW_CFG_SPEED_CAPABILITY_D0_1G))) {
+
+ DP(NETIF_MSG_LINK, "Setting 1G clause37 \n");
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_PMA_REG_8727_MISC_CTRL, 0);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CL37_AN, 0x1300);
+ } else {
+ /* Since the 8727 has only single reset pin,
+ need to set the 10G registers although it is
+ default */
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ MDIO_AN_REG_CTRL, 0x0020);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_AN_DEVAD,
+ 0x7, 0x0100);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL, 0x2040);
+ bnx2x_cl45_write(bp, params->port, ext_phy_type,
+ ext_phy_addr, MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_10G_CTRL2, 0x0008);
+ }
+
+ /* Set 2-wire transfer rate to 400Khz since 100Khz
+ is not operational */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR,
+ 0xa101);
+
+ /* Set TX PreEmphasis if needed */
+ if ((params->feature_config_flags &
+ FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) {
+ DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x,"
+ "TX_CTRL2 0x%x\n",
+ params->xgxs_config_tx[0],
+ params->xgxs_config_tx[1]);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TX_CTRL1,
+ params->xgxs_config_tx[0]);
+
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_TX_CTRL2,
+ params->xgxs_config_tx[1]);
+ }
+
+ break;
+ }
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
{
u16 fw_ver1, fw_ver2;
@@ -3561,6 +4009,99 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
return rc;
}
+static void bnx2x_8727_handle_mod_abs(struct link_params *params)
+{
+ struct bnx2x *bp = params->bp;
+ u16 mod_abs, rx_alarm_status;
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs);
+ if (mod_abs & (1<<8)) {
+
+ /* Module is absent */
+ DP(NETIF_MSG_LINK, "MOD_ABS indication "
+ "show module is absent\n");
+
+ /* 1. Set mod_abs to detect next module
+ presence event
+ 2. Set EDC off by setting OPTXLOS signal input to low
+ (bit 9).
+ When the EDC is off it locks onto a reference clock and
+ avoids becoming 'lost'.*/
+ mod_abs &= ~((1<<8)|(1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Clear RX alarm since it stays up as long as
+ the mod_abs wasn't changed */
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+ } else {
+ /* Module is present */
+ DP(NETIF_MSG_LINK, "MOD_ABS indication "
+ "show module is present\n");
+ /* First thing, disable transmitter,
+ and if the module is ok, the
+ module_detection will enable it*/
+
+ /* 1. Set mod_abs to detect next module
+ absent event ( bit 8)
+ 2. Restore the default polarity of the OPRXLOS signal and
+ this signal will then correctly indicate the presence or
+ absence of the Rx signal. (bit 9) */
+ mod_abs |= ((1<<8)|(1<<9));
+ bnx2x_cl45_write(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs);
+
+ /* Clear RX alarm since it stays up as long as
+ the mod_abs wasn't changed. This is need to be done
+ before calling the module detection, otherwise it will clear
+ the link update alarm */
+ bnx2x_cl45_read(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, params->port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr, 0);
+
+ if (bnx2x_wait_for_sfp_module_initialized(params)
+ == 0)
+ bnx2x_sfp_module_detection(params);
+ else
+ DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n");
+ }
+
+ DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+ rx_alarm_status);
+ /* No need to check link status in case of
+ module plugged in/out */
+}
+
static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
struct link_vars *vars)
@@ -3602,8 +4143,19 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_RX_SD, &rx_sd);
- DP(NETIF_MSG_LINK, "8705 rx_sd 0x%x\n", rx_sd);
- ext_phy_link_up = (rx_sd & 0x1);
+
+ bnx2x_cl45_read(bp, params->port, ext_phy_type,
+ ext_phy_addr,
+ 1,
+ 0xc809, &val1);
+ bnx2x_cl45_read(bp, params->port, ext_phy_type,
+ ext_phy_addr,
+ 1,
+ 0xc809, &val1);
+
+ DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1);
+ ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9))
+ && ((val1 & (1<<8)) == 0));
if (ext_phy_link_up)
vars->line_speed = SPEED_10000;
break;
@@ -3678,8 +4230,160 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params,
else
vars->line_speed = SPEED_10000;
}
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+ u16 link_status = 0;
+ u16 rx_alarm_status;
+ /* Check the LASI */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM, &rx_alarm_status);
+
+ DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n",
+ rx_alarm_status);
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_LASI_STATUS, &val1);
+
+ DP(NETIF_MSG_LINK,
+ "8727 LASI status 0x%x\n",
+ val1);
+
+ /* Clear MSG-OUT */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_M8051_MSGOUT_REG,
+ &val1);
+
+ /*
+ * If a module is present and there is need to check
+ * for over current
+ */
+ if (!(params->feature_config_flags &
+ FEATURE_CONFIG_BCM8727_NOC) &&
+ !(rx_alarm_status & (1<<5))) {
+ /* Check over-current using 8727 GPIO0 input*/
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8727_GPIO_CTRL,
+ &val1);
+
+ if ((val1 & (1<<8)) == 0) {
+ DP(NETIF_MSG_LINK, "8727 Power fault"
+ " has been detected on port"
+ " %d\n", params->port);
+ printk(KERN_ERR PFX "Error: Power"
+ " fault on %s Port %d has"
+ " been detected and the"
+ " power to that SFP+ module"
+ " has been removed to prevent"
+ " failure of the card. Please"
+ " remove the SFP+ module and"
+ " restart the system to clear"
+ " this error.\n"
+ , bp->dev->name, params->port);
+ /*
+ * Disable all RX_ALARMs except for
+ * mod_abs
+ */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ (1<<5));
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &val1);
+ /* Wait for module_absent_event */
+ val1 |= (1<<8);
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ val1);
+ /* Clear RX alarm */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM,
+ &rx_alarm_status);
+ break;
+ }
+ } /* Over current check */
+
+ /* When module absent bit is set, check module */
+ if (rx_alarm_status & (1<<5)) {
+ bnx2x_8727_handle_mod_abs(params);
+ /* Enable all mod_abs and link detection bits */
+ bnx2x_cl45_write(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_RX_ALARM_CTRL,
+ ((1<<5) | (1<<2)));
+ }
+
+ /* If transmitter is disabled,
+ ignore false link up indication */
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_PHY_IDENTIFIER,
+ &val1);
+ if (val1 & (1<<15)) {
+ DP(NETIF_MSG_LINK, "Tx is disabled\n");
+ ext_phy_link_up = 0;
+ break;
+ }
+
+ bnx2x_cl45_read(bp, params->port,
+ ext_phy_type,
+ ext_phy_addr,
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_8073_SPEED_LINK_STATUS,
+ &link_status);
+ /* Bits 0..2 --> speed detected,
+ bits 13..15--> link is down */
+ if ((link_status & (1<<2)) &&
+ (!(link_status & (1<<15)))) {
+ ext_phy_link_up = 1;
+ vars->line_speed = SPEED_10000;
+ } else if ((link_status & (1<<0)) &&
+ (!(link_status & (1<<13)))) {
+ ext_phy_link_up = 1;
+ vars->line_speed = SPEED_1000;
+ DP(NETIF_MSG_LINK,
+ "port %x: External link"
+ " up in 1G\n", params->port);
+ } else {
+ ext_phy_link_up = 0;
+ DP(NETIF_MSG_LINK,
+ "port %x: External link"
+ " is down\n", params->port);
+ }
break;
+ }
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
{
@@ -4242,6 +4946,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
@@ -4790,6 +5495,11 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
}
REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE +
params->port*4, 0);
+
+ bnx2x_set_led(bp, params->port, LED_MODE_OPER,
+ vars->line_speed, params->hw_led_mode,
+ params->chip_id);
+
} else
/* No loopback */
{
@@ -4843,10 +5553,6 @@ static void bnx2x_8726_reset_phy(struct bnx2x *bp, u8 port, u8 ext_phy_addr)
PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, ext_phy_addr,
MDIO_PMA_DEVAD,
MDIO_PMA_REG_GEN_CTRL, 0x0001);
-
- /* Disable Transmitter */
- bnx2x_bcm8726_set_transmitter(bp, port, ext_phy_addr, 0);
-
}
u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
@@ -4859,6 +5565,11 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
u32 chip_id = params->chip_id;
u8 port = params->port;
u32 ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config);
+ u32 val = REG_RD(bp, params->shmem_base +
+ offsetof(struct shmem_region, dev_info.
+ port_feature_config[params->port].
+ config));
+
/* disable attentions */
vars->link_status = 0;
@@ -4893,6 +5604,21 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ {
+
+ /* Disable Transmitter */
+ u8 ext_phy_addr = ((params->ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+ if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+ PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
+ bnx2x_sfp_set_transmitter(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr, 0);
+ break;
+ }
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
DP(NETIF_MSG_LINK, "Setting 8073 port %d into "
"low power mode\n",
@@ -5217,6 +5943,74 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, u32 shmem_base)
}
+static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, u32 shmem_base)
+{
+ u8 ext_phy_addr[PORT_MAX];
+ s8 port;
+ u32 swap_val, swap_override;
+ DP(NETIF_MSG_LINK, "Executing BCM8727 common init\n");
+ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+ swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+
+ bnx2x_hw_reset(bp, 1 ^ (swap_val && swap_override));
+ msleep(5);
+
+ /* PART1 - Reset both phys */
+ for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+ /* Extract the ext phy address for the port */
+ u32 ext_phy_config = REG_RD(bp, shmem_base +
+ offsetof(struct shmem_region,
+ dev_info.port_hw_config[port].external_phy_config));
+
+ /* disable attentions */
+ bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+ (NIG_MASK_XGXS0_LINK_STATUS |
+ NIG_MASK_XGXS0_LINK10G |
+ NIG_MASK_SERDES0_LINK_STATUS |
+ NIG_MASK_MI_INT));
+
+ ext_phy_addr[port] = ((ext_phy_config &
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
+ PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
+
+ /* Reset the phy */
+ bnx2x_cl45_write(bp, port,
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr[port],
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_CTRL,
+ 1<<15);
+ }
+
+ /* Add delay of 150ms after reset */
+ msleep(150);
+
+ /* PART2 - Download firmware to both phys */
+ for (port = PORT_MAX - 1; port >= PORT_0; port--) {
+ u16 fw_ver1;
+
+ bnx2x_bcm8727_external_rom_boot(bp, port,
+ ext_phy_addr[port], shmem_base);
+
+ bnx2x_cl45_read(bp, port, PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
+ ext_phy_addr[port],
+ MDIO_PMA_DEVAD,
+ MDIO_PMA_REG_ROM_VER1, &fw_ver1);
+ if (fw_ver1 == 0 || fw_ver1 == 0x4321) {
+ DP(NETIF_MSG_LINK,
+ "bnx2x_8073_common_init_phy port %x:"
+ "Download failed. fw version = 0x%x\n",
+ port, fw_ver1);
+ return -EINVAL;
+ }
+
+ }
+
+
+
+ return 0;
+}
+
static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, u32 shmem_base)
{
@@ -5275,6 +6069,12 @@ u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base)
rc = bnx2x_8073_common_init_phy(bp, shmem_base);
break;
}
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
+ rc = bnx2x_8727_common_init_phy(bp, shmem_base);
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
/* GPIO1 affects both ports, so there's need to pull
it for single port alone */
diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h
index 19a866dc10e..d25ef45d793 100644
--- a/drivers/net/bnx2x_link.h
+++ b/drivers/net/bnx2x_link.h
@@ -39,7 +39,13 @@
#define SPEED_15000 15000
#define SPEED_16000 16000
-
+#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14
+#define SFP_EEPROM_VENDOR_NAME_SIZE 16
+#define SFP_EEPROM_VENDOR_OUI_ADDR 0x25
+#define SFP_EEPROM_VENDOR_OUI_SIZE 3
+#define SFP_EEPROM_PART_NO_ADDR 0x28
+#define SFP_EEPROM_PART_NO_SIZE 16
+#define PWR_FLT_ERR_MSG_LEN 250
/***********************************************************/
/* Structs */
/***********************************************************/
@@ -91,7 +97,8 @@ struct link_params {
u16 xgxs_config_tx[4]; /* preemphasis values for the tx side */
u32 feature_config_flags;
#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0)
-#define FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED (2<<0)
+#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2)
+#define FEATURE_CONFIG_BCM8727_NOC (1<<3)
/* Device pointer passed to all callback functions */
struct bnx2x *bp;
};
@@ -181,4 +188,7 @@ u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars);
u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base);
+u8 bnx2x_read_sfp_module_eeprom(struct link_params *params, u16 addr,
+ u8 byte_cnt, u8 *o_buf);
+
#endif /* BNX2X_LINK_H */
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 6c67be67976..2d035d795f0 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -56,8 +56,8 @@
#include "bnx2x_init_ops.h"
#include "bnx2x_dump.h"
-#define DRV_MODULE_VERSION "1.48.105-1"
-#define DRV_MODULE_RELDATE "2009/04/22"
+#define DRV_MODULE_VERSION "1.48.114-1"
+#define DRV_MODULE_RELDATE "2009/07/29"
#define BNX2X_BC_VER 0x040200
#include <linux/firmware.h>
@@ -652,6 +652,11 @@ static void bnx2x_int_enable(struct bnx2x *bp)
val, port, addr, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));
REG_WR(bp, addr, val);
+ /*
+ * Ensure that HC_CONFIG is written before leading/trailing edge config
+ */
+ mmiowb();
+ barrier();
if (CHIP_IS_E1H(bp)) {
/* init leading/trailing edge */
@@ -666,6 +671,9 @@ static void bnx2x_int_enable(struct bnx2x *bp)
REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
}
+
+ /* Make sure that interrupts are indeed enabled from here on */
+ mmiowb();
}
static void bnx2x_int_disable(struct bnx2x *bp)
@@ -698,6 +706,8 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
/* disable interrupt handling */
atomic_inc(&bp->intr_sem);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
if (disable_hw)
/* prevent the HW from sending interrupts */
bnx2x_int_disable(bp);
@@ -739,6 +749,10 @@ static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 sb_id,
DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n",
(*(u32 *)&igu_ack), hc_addr);
REG_WR(bp, hc_addr, (*(u32 *)&igu_ack));
+
+ /* Make sure that ACK is written */
+ mmiowb();
+ barrier();
}
static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
@@ -2429,9 +2443,14 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
bp->spq_prod_idx++;
}
+ /* Make sure that BD data is updated before writing the producer */
+ wmb();
+
REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
bp->spq_prod_idx);
+ mmiowb();
+
spin_unlock_bh(&bp->spq_lock);
return 0;
}
@@ -2598,11 +2617,27 @@ static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted)
}
}
+static inline void bnx2x_fan_failure(struct bnx2x *bp)
+{
+ int port = BP_PORT(bp);
+
+ /* mark the failure */
+ bp->link_params.ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ bp->link_params.ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
+ SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config,
+ bp->link_params.ext_phy_config);
+
+ /* log the failure */
+ printk(KERN_ERR PFX "Fan Failure on Network Controller %s has caused"
+ " the driver to shutdown the card to prevent permanent"
+ " damage. Please contact Dell Support for assistance\n",
+ bp->dev->name);
+}
static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
{
int port = BP_PORT(bp);
int reg_offset;
- u32 val;
+ u32 val, swap_val, swap_override;
reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
@@ -2615,36 +2650,32 @@ static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
BNX2X_ERR("SPIO5 hw attention\n");
+ /* Fan failure attention */
switch (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config)) {
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* Fan failure attention */
-
+ /* Low power mode is controlled by GPIO 2 */
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
/* The PHY reset is controlled by GPIO 1 */
bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- /* Low power mode is controlled by GPIO 2 */
- bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2,
+ break;
+
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ /* The PHY reset is controlled by GPIO 1 */
+ /* fake the port number to cancel the swap done in
+ set_gpio() */
+ swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+ swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+ port = (swap_val && swap_override) ^ 1;
+ bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1,
MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
- /* mark the failure */
- bp->link_params.ext_phy_config &=
- ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
- bp->link_params.ext_phy_config |=
- PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE;
- SHMEM_WR(bp,
- dev_info.port_hw_config[port].
- external_phy_config,
- bp->link_params.ext_phy_config);
- /* log the failure */
- printk(KERN_ERR PFX "Fan Failure on Network"
- " Controller %s has caused the driver to"
- " shutdown the card to prevent permanent"
- " damage. Please contact Dell Support for"
- " assistance\n", bp->dev->name);
break;
default:
break;
}
+ bnx2x_fan_failure(bp);
}
if (attn & (AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 |
@@ -4800,7 +4831,14 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
int mode = bp->rx_mode;
int mask = (1 << BP_L_ID(bp));
int func = BP_FUNC(bp);
+ int port = BP_PORT(bp);
int i;
+ /* All but management unicast packets should pass to the host as well */
+ u32 llh_mask =
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN |
+ NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN;
DP(NETIF_MSG_IFUP, "rx mode %d mask 0x%x\n", mode, mask);
@@ -4824,6 +4862,8 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
tstorm_mac_filter.ucast_accept_all = mask;
tstorm_mac_filter.mcast_accept_all = mask;
tstorm_mac_filter.bcast_accept_all = mask;
+ /* pass management unicast packets as well */
+ llh_mask |= NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST;
break;
default:
@@ -4831,6 +4871,10 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
break;
}
+ REG_WR(bp,
+ (port ? NIG_REG_LLH1_BRB1_DRV_MASK : NIG_REG_LLH0_BRB1_DRV_MASK),
+ llh_mask);
+
for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) {
REG_WR(bp, BAR_TSTRORM_INTMEM +
TSTORM_MAC_FILTER_CONFIG_OFFSET(func) + i * 4,
@@ -5184,6 +5228,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
mmiowb();
bnx2x_int_enable(bp);
+
+ /* Check for SPIO5 */
+ bnx2x_attn_int_deasserted0(bp,
+ REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) &
+ AEU_INPUTS_ATTN_BITS_SPIO5);
}
/* end of nic init */
@@ -5509,6 +5558,60 @@ static void bnx2x_reset_common(struct bnx2x *bp)
REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, 0x1403);
}
+
+static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
+{
+ u32 val;
+ u8 port;
+ u8 is_required = 0;
+
+ val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) &
+ SHARED_HW_CFG_FAN_FAILURE_MASK;
+
+ if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED)
+ is_required = 1;
+
+ /*
+ * The fan failure mechanism is usually related to the PHY type since
+ * the power consumption of the board is affected by the PHY. Currently,
+ * fan is required for most designs with SFX7101, BCM8727 and BCM8481.
+ */
+ else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE)
+ for (port = PORT_0; port < PORT_MAX; port++) {
+ u32 phy_type =
+ SHMEM_RD(bp, dev_info.port_hw_config[port].
+ external_phy_config) &
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ is_required |=
+ ((phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) ||
+ (phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
+ (phy_type ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481));
+ }
+
+ DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required);
+
+ if (is_required == 0)
+ return;
+
+ /* Fan failure is indicated by SPIO 5 */
+ bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
+ MISC_REGISTERS_SPIO_INPUT_HI_Z);
+
+ /* set to active low mode */
+ val = REG_RD(bp, MISC_REG_SPIO_INT);
+ val |= ((1 << MISC_REGISTERS_SPIO_5) <<
+ MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
+ REG_WR(bp, MISC_REG_SPIO_INT, val);
+
+ /* enable interrupt to signal the IGU */
+ val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
+ val |= (1 << MISC_REGISTERS_SPIO_5);
+ REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
+}
+
static int bnx2x_init_common(struct bnx2x *bp)
{
u32 val, i;
@@ -5735,30 +5838,16 @@ static int bnx2x_init_common(struct bnx2x *bp)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
bp->port.need_hw_lock = 1;
break;
- case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
- /* Fan failure is indicated by SPIO 5 */
- bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5,
- MISC_REGISTERS_SPIO_INPUT_HI_Z);
-
- /* set to active low mode */
- val = REG_RD(bp, MISC_REG_SPIO_INT);
- val |= ((1 << MISC_REGISTERS_SPIO_5) <<
- MISC_REGISTERS_SPIO_INT_OLD_SET_POS);
- REG_WR(bp, MISC_REG_SPIO_INT, val);
-
- /* enable interrupt to signal the IGU */
- val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN);
- val |= (1 << MISC_REGISTERS_SPIO_5);
- REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val);
- break;
-
default:
break;
}
+ bnx2x_setup_fan_failure_detection(bp);
+
/* clear PXP2 attentions */
REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0);
@@ -5988,10 +6077,15 @@ static int bnx2x_init_port(struct bnx2x *bp)
break;
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
/* add SPIO 5 to group 0 */
- val = REG_RD(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ {
+ u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 :
+ MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0);
+ val = REG_RD(bp, reg_addr);
val |= AEU_INPUTS_ATTN_BITS_SPIO5;
- REG_WR(bp, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, val);
+ REG_WR(bp, reg_addr, val);
+ }
break;
default:
@@ -6141,7 +6235,7 @@ init_hw_err:
}
/* send the MCP a request, block until there is a reply */
-static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
+u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
{
int func = BP_FUNC(bp);
u32 seq = ++bp->fw_seq;
@@ -6582,7 +6676,12 @@ static void bnx2x_napi_disable(struct bnx2x *bp)
static void bnx2x_netif_start(struct bnx2x *bp)
{
- if (atomic_dec_and_test(&bp->intr_sem)) {
+ int intr_sem;
+
+ intr_sem = atomic_dec_and_test(&bp->intr_sem);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
+
+ if (intr_sem) {
if (netif_running(bp->dev)) {
bnx2x_napi_enable(bp);
bnx2x_int_enable(bp);
@@ -7255,17 +7354,17 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
for (i = 0; i < MC_HASH_SIZE; i++)
REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
+
+ REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
}
if (unload_mode == UNLOAD_NORMAL)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
- else if (bp->flags & NO_WOL_FLAG) {
+ else if (bp->flags & NO_WOL_FLAG)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP;
- if (CHIP_IS_E1H(bp))
- REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
- } else if (bp->wol) {
+ else if (bp->wol) {
u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
u8 *mac_addr = bp->dev->dev_addr;
u32 val;
@@ -7609,6 +7708,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
BNX2X_ERR("This driver needs bc_ver %X but found %X,"
" please upgrade BC\n", BNX2X_BC_VER, val);
}
+ bp->link_params.feature_config_flags |=
+ (val >= REQ_BC_VER_4_VRFY_OPT_MDL) ?
+ FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0;
if (BP_E1HVN(bp) == 0) {
pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
@@ -7769,6 +7871,18 @@ static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp,
SUPPORTED_Asym_Pause);
break;
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+ BNX2X_DEV_INFO("ext_phy_type 0x%x (8727)\n",
+ ext_phy_type);
+
+ bp->port.supported |= (SUPPORTED_10000baseT_Full |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_Autoneg |
+ SUPPORTED_FIBRE |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause);
+ break;
+
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101:
BNX2X_DEV_INFO("ext_phy_type 0x%x (SFX7101)\n",
ext_phy_type);
@@ -8032,6 +8146,17 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.ext_phy_config =
SHMEM_RD(bp,
dev_info.port_hw_config[port].external_phy_config);
+ /* BCM8727_NOC => BCM8727 no over current */
+ if (XGXS_EXT_PHY_TYPE(bp->link_params.ext_phy_config) ==
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC) {
+ bp->link_params.ext_phy_config &=
+ ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK;
+ bp->link_params.ext_phy_config |=
+ PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727;
+ bp->link_params.feature_config_flags |=
+ FEATURE_CONFIG_BCM8727_NOC;
+ }
+
bp->link_params.speed_cap_mask =
SHMEM_RD(bp,
dev_info.port_hw_config[port].speed_capability_mask);
@@ -8052,17 +8177,10 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.xgxs_config_tx[(i << 1) + 1] = (val & 0xffff);
}
- config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
- if (config & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_ENABLED)
- bp->link_params.feature_config_flags |=
- FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
- else
- bp->link_params.feature_config_flags &=
- ~FEATURE_CONFIG_MODULE_ENFORCMENT_ENABLED;
-
/* If the device is capable of WoL, set the default state according
* to the HW
*/
+ config = SHMEM_RD(bp, dev_info.port_feature_config[port].config);
bp->wol = (!(bp->flags & NO_WOL_FLAG) &&
(config & PORT_FEATURE_WOL_ENABLED));
@@ -8072,8 +8190,8 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bp->link_params.ext_phy_config,
bp->link_params.speed_cap_mask, bp->port.link_config);
- bp->link_params.switch_cfg = (bp->port.link_config &
- PORT_FEATURE_CONNECTED_SWITCH_MASK);
+ bp->link_params.switch_cfg |= (bp->port.link_config &
+ PORT_FEATURE_CONNECTED_SWITCH_MASK);
bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg);
bnx2x_link_settings_requested(bp);
@@ -8169,6 +8287,7 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
/* Disable interrupt handling until HW is initialized */
atomic_set(&bp->intr_sem, 1);
+ smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
mutex_init(&bp->port.phy_mutex);
@@ -8268,6 +8387,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+ case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
cmd->port = PORT_FIBRE;
break;
@@ -9295,10 +9415,9 @@ static int bnx2x_test_registers(struct bnx2x *bp)
{ XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 },
{ XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 },
{ XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff },
- { NIG_REG_EGRESS_MNG0_FIFO, 20, 0xffffffff },
{ NIG_REG_LLH0_T_BIT, 4, 0x00000001 },
-/* 20 */ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 },
- { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 },
+ { NIG_REG_EMAC0_IN_EN, 4, 0x00000001 },
+/* 20 */ { NIG_REG_BMAC0_IN_EN, 4, 0x00000001 },
{ NIG_REG_XCM0_OUT_EN, 4, 0x00000001 },
{ NIG_REG_BRB0_OUT_EN, 4, 0x00000001 },
{ NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 },
@@ -9307,8 +9426,8 @@ static int bnx2x_test_registers(struct bnx2x *bp)
{ NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff },
{ NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff },
{ NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 },
-/* 30 */ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff },
- { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff },
+ { NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff },
+/* 30 */ { NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff },
{ NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff },
{ NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 },
{ NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001 },
@@ -9691,8 +9810,15 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags &= ~ETH_TEST_FL_OFFLINE;
if (etest->flags & ETH_TEST_FL_OFFLINE) {
+ int port = BP_PORT(bp);
+ u32 val;
u8 link_up;
+ /* save current value of input enable for TX port IF */
+ val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4);
+ /* disable input for TX port IF */
+ REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0);
+
link_up = bp->link_vars.link_up;
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
bnx2x_nic_load(bp, LOAD_DIAG);
@@ -9712,6 +9838,10 @@ static void bnx2x_self_test(struct net_device *dev,
etest->flags |= ETH_TEST_FL_FAILED;
bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+
+ /* restore input for TX port IF */
+ REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val);
+
bnx2x_nic_load(bp, LOAD_NORMAL);
/* wait until link state is restored */
bnx2x_wait_for_link(bp, link_up);
@@ -11064,12 +11194,19 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->features |= NETIF_F_HW_CSUM;
if (bp->flags & USING_DAC_FLAG)
dev->features |= NETIF_F_HIGHDMA;
+ dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+ dev->features |= NETIF_F_TSO6;
#ifdef BCM_VLAN
dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
bp->flags |= (HW_VLAN_RX_FLAG | HW_VLAN_TX_FLAG);
+
+ dev->vlan_features |= NETIF_F_SG;
+ dev->vlan_features |= NETIF_F_HW_CSUM;
+ if (bp->flags & USING_DAC_FLAG)
+ dev->vlan_features |= NETIF_F_HIGHDMA;
+ dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
+ dev->vlan_features |= NETIF_F_TSO6;
#endif
- dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
- dev->features |= NETIF_F_TSO6;
return 0;
diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h
index b8ce6fc927a..8e9e7a24f2f 100644
--- a/drivers/net/bnx2x_reg.h
+++ b/drivers/net/bnx2x_reg.h
@@ -1616,6 +1616,11 @@
/* [RW 1] Set by the MCP to remember if one or more of the drivers is/are
loaded; 0-prepare; -unprepare */
#define MISC_REG_UNPREPARED 0xa424
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST (0x1<<0)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST (0x1<<1)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2)
+#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9)
#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15)
@@ -1660,6 +1665,8 @@
#define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc
/* [RW 1] Input enable for TX PBF user packet port1 IF */
#define NIG_REG_EGRESS_PBF1_IN_EN 0x100d0
+/* [RW 1] Input enable for TX UMP management packet port0 IF */
+#define NIG_REG_EGRESS_UMP0_IN_EN 0x100d4
/* [RW 1] Input enable for RX_EMAC0 IF */
#define NIG_REG_EMAC0_IN_EN 0x100a4
/* [RW 1] output enable for TX EMAC pause port 0 IF */
@@ -5843,25 +5850,33 @@ Theotherbitsarereservedandshouldbezero*/
#define MDIO_PMA_REG_ROM_VER2 0xca1a
#define MDIO_PMA_REG_EDC_FFE_MAIN 0xca1b
#define MDIO_PMA_REG_PLL_BANDWIDTH 0xca1d
-#define MDIO_PMA_REG_GEN_CTRL2 0xca1e
+#define MDIO_PMA_REG_PLL_CTRL 0xca1e
#define MDIO_PMA_REG_MISC_CTRL0 0xca23
#define MDIO_PMA_REG_LRM_MODE 0xca3f
#define MDIO_PMA_REG_CDR_BANDWIDTH 0xca46
#define MDIO_PMA_REG_MISC_CTRL1 0xca85
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL 0x8000
-#define MDIO_PMA_REG_8726_TWO_WIRE_CTRL_STATUS_MASK 0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IDLE 0x0000
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_COMPLETE 0x0004
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_IN_PROGRESS 0x0008
-#define MDIO_PMA_REG_8726_TWO_WIRE_STATUS_FAILED 0x000c
-#define MDIO_PMA_REG_8726_TWO_WIRE_BYTE_CNT 0x8002
-#define MDIO_PMA_REG_8726_TWO_WIRE_MEM_ADDR 0x8003
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL 0x8000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK 0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE 0x0000
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE 0x0004
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IN_PROGRESS 0x0008
+#define MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_FAILED 0x000c
+#define MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT 0x8002
+#define MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR 0x8003
#define MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF 0xc820
#define MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK 0xff
#define MDIO_PMA_REG_8726_TX_CTRL1 0xca01
#define MDIO_PMA_REG_8726_TX_CTRL2 0xca05
+#define MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR 0x8005
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF 0x8007
+#define MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK 0xff
+#define MDIO_PMA_REG_8727_MISC_CTRL 0x8309
+#define MDIO_PMA_REG_8727_TX_CTRL1 0xca02
+#define MDIO_PMA_REG_8727_TX_CTRL2 0xca05
+#define MDIO_PMA_REG_8727_PCS_OPT_CTRL 0xc808
+#define MDIO_PMA_REG_8727_GPIO_CTRL 0xc80e
#define MDIO_PMA_REG_8073_CHIP_REV 0xc801
#define MDIO_PMA_REG_8073_SPEED_LINK_STATUS 0xc820
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index d4b570886c6..be799d2a8a8 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -1109,7 +1109,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
//mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port.
port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION;
port->sm_vars &= ~AD_PORT_MATCHED;
- port->partner_oper.port_state |= AD_SHORT_TIMEOUT;
+ port->partner_oper.port_state |=
+ AD_STATE_LACP_ACTIVITY;
port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT));
port->actor_oper_port_state |= AD_STATE_EXPIRED;
break;
@@ -2431,7 +2432,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 46d312bedfb..bf45d200292 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1413,7 +1413,7 @@ out:
}
read_unlock(&bond->curr_slave_lock);
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
void bond_alb_monitor(struct work_struct *work)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index aa1be1fecee..3bf0cc61e92 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -4285,7 +4285,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -4316,7 +4316,7 @@ out:
read_unlock(&bond->curr_slave_lock);
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -4362,7 +4362,7 @@ out:
dev_kfree_skb(skb);
}
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -4422,7 +4422,7 @@ out:
/* frame sent to all suitable interfaces */
read_unlock(&bond->lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*------------------------- Device initialization ---------------------------*/
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index 33821a81cbf..30ae55d7167 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -61,11 +61,12 @@ config CAN_SJA1000_OF_PLATFORM
you may want to enable this option.
config CAN_EMS_PCI
- tristate "EMS CPC-PCI and CPC-PCIe Card"
+ tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card"
depends on PCI && CAN_SJA1000
---help---
- This driver is for the one or two channel CPC-PCI and CPC-PCIe
- cards from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de).
+ This driver is for the one, two or four channel CPC-PCI,
+ CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche
+ (http://www.ems-wuensche.de).
config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
diff --git a/drivers/net/can/sja1000/ems_pci.c b/drivers/net/can/sja1000/ems_pci.c
index 121b64101d7..7d84b8ac9c1 100644
--- a/drivers/net/can/sja1000/ems_pci.c
+++ b/drivers/net/can/sja1000/ems_pci.c
@@ -32,13 +32,16 @@
#define DRV_NAME "ems_pci"
MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe CAN cards");
-MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe CAN card");
+MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards");
+MODULE_SUPPORTED_DEVICE("EMS CPC-PCI/PCIe/104P CAN card");
MODULE_LICENSE("GPL v2");
-#define EMS_PCI_MAX_CHAN 2
+#define EMS_PCI_V1_MAX_CHAN 2
+#define EMS_PCI_V2_MAX_CHAN 4
+#define EMS_PCI_MAX_CHAN EMS_PCI_V2_MAX_CHAN
struct ems_pci_card {
+ int version;
int channels;
struct pci_dev *pci_dev;
@@ -63,12 +66,22 @@ struct ems_pci_card {
#define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */
/*
+ * Register definitions for the PLX 9030
+ */
+#define PLX_ICSR 0x4c /* Interrupt Control/Status register */
+#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
+#define PLX_ICSR_PCIINT_ENA 0x0040 /* PCI Interrupt Enable */
+#define PLX_ICSR_LINTI1_CLR 0x0400 /* Local Edge Triggerable Interrupt Clear */
+#define PLX_ICSR_ENA_CLR (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
+ PLX_ICSR_LINTI1_CLR)
+
+/*
* The board configuration is probably following:
* RX1 is connected to ground.
* TX1 is not connected.
* CLKO is not connected.
* Setting the OCR register to 0xDA is a good idea.
- * This means normal output mode , push-pull and the correct polarity.
+ * This means normal output mode, push-pull and the correct polarity.
*/
#define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
@@ -79,17 +92,21 @@ struct ems_pci_card {
* is driven by the first one CLKOUT output.
*/
#define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
-#define EMS_PCI_MEM_SIZE 4096 /* Size of the remapped io-memory */
+
+#define EMS_PCI_V1_BASE_BAR 1
+#define EMS_PCI_V1_MEM_SIZE 4096
+#define EMS_PCI_V2_BASE_BAR 2
+#define EMS_PCI_V2_MEM_SIZE 128
#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
#define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */
-#define EMS_PCI_PORT_BYTES 0x4 /* Each register occupies 4 bytes */
-
-#define EMS_PCI_VENDOR_ID 0x110a /* PCI device and vendor ID */
-#define EMS_PCI_DEVICE_ID 0x2104
-
static struct pci_device_id ems_pci_tbl[] = {
- {EMS_PCI_VENDOR_ID, EMS_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ /* CPC-PCI v1 */
+ {PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
+ /* CPC-PCI v2 */
+ {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000},
+ /* CPC-104P v2 */
+ {PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002},
{0,}
};
MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
@@ -97,28 +114,47 @@ MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
/*
* Helper to read internal registers from card logic (not CAN)
*/
-static u8 ems_pci_readb(struct ems_pci_card *card, unsigned int port)
+static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port)
{
- return readb(card->base_addr + (port * EMS_PCI_PORT_BYTES));
+ return readb(card->base_addr + (port * 4));
}
-static u8 ems_pci_read_reg(const struct sja1000_priv *priv, int port)
+static u8 ems_pci_v1_read_reg(const struct sja1000_priv *priv, int port)
{
- return readb(priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+ return readb(priv->reg_base + (port * 4));
}
-static void ems_pci_write_reg(const struct sja1000_priv *priv, int port, u8 val)
+static void ems_pci_v1_write_reg(const struct sja1000_priv *priv,
+ int port, u8 val)
{
- writeb(val, priv->reg_base + (port * EMS_PCI_PORT_BYTES));
+ writeb(val, priv->reg_base + (port * 4));
}
-static void ems_pci_post_irq(const struct sja1000_priv *priv)
+static void ems_pci_v1_post_irq(const struct sja1000_priv *priv)
{
struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
/* reset int flag of pita */
- writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0, card->conf_addr
- + PITA2_ICR);
+ writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+ card->conf_addr + PITA2_ICR);
+}
+
+static u8 ems_pci_v2_read_reg(const struct sja1000_priv *priv, int port)
+{
+ return readb(priv->reg_base + port);
+}
+
+static void ems_pci_v2_write_reg(const struct sja1000_priv *priv,
+ int port, u8 val)
+{
+ writeb(val, priv->reg_base + port);
+}
+
+static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
+{
+ struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
+
+ writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
}
/*
@@ -130,12 +166,12 @@ static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
unsigned char res;
/* Make sure SJA1000 is in reset mode */
- ems_pci_write_reg(priv, REG_MOD, 1);
+ priv->write_reg(priv, REG_MOD, 1);
- ems_pci_write_reg(priv, REG_CDR, CDR_PELICAN);
+ priv->write_reg(priv, REG_CDR, CDR_PELICAN);
/* read reset-values */
- res = ems_pci_read_reg(priv, REG_CDR);
+ res = priv->read_reg(priv, REG_CDR);
if (res == CDR_PELICAN)
return 1;
@@ -188,6 +224,7 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
struct sja1000_priv *priv;
struct net_device *dev;
struct ems_pci_card *card;
+ int max_chan, mem_size, base_bar;
int err, i;
/* Enabling PCI device */
@@ -210,37 +247,52 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
card->channels = 0;
- /* Remap PITA configuration space, and controller memory area */
- card->conf_addr = pci_iomap(pdev, 0, EMS_PCI_MEM_SIZE);
+ if (pdev->vendor == PCI_VENDOR_ID_PLX) {
+ card->version = 2; /* CPC-PCI v2 */
+ max_chan = EMS_PCI_V2_MAX_CHAN;
+ base_bar = EMS_PCI_V2_BASE_BAR;
+ mem_size = EMS_PCI_V2_MEM_SIZE;
+ } else {
+ card->version = 1; /* CPC-PCI v1 */
+ max_chan = EMS_PCI_V1_MAX_CHAN;
+ base_bar = EMS_PCI_V1_BASE_BAR;
+ mem_size = EMS_PCI_V1_MEM_SIZE;
+ }
+
+ /* Remap configuration space and controller memory area */
+ card->conf_addr = pci_iomap(pdev, 0, mem_size);
if (card->conf_addr == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
- card->base_addr = pci_iomap(pdev, 1, EMS_PCI_MEM_SIZE);
+ card->base_addr = pci_iomap(pdev, base_bar, mem_size);
if (card->base_addr == NULL) {
err = -ENOMEM;
goto failure_cleanup;
}
- /* Configure PITA-2 parallel interface (enable MUX) */
- writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
-
- /* Check for unique EMS CAN signature */
- if (ems_pci_readb(card, 0) != 0x55 ||
- ems_pci_readb(card, 1) != 0xAA ||
- ems_pci_readb(card, 2) != 0x01 ||
- ems_pci_readb(card, 3) != 0xCB ||
- ems_pci_readb(card, 4) != 0x11) {
- dev_err(&pdev->dev, "Not EMS Dr. Thomas Wuensche interface\n");
- err = -ENODEV;
- goto failure_cleanup;
+ if (card->version == 1) {
+ /* Configure PITA-2 parallel interface (enable MUX) */
+ writel(PITA2_MISC_CONFIG, card->conf_addr + PITA2_MISC);
+
+ /* Check for unique EMS CAN signature */
+ if (ems_pci_v1_readb(card, 0) != 0x55 ||
+ ems_pci_v1_readb(card, 1) != 0xAA ||
+ ems_pci_v1_readb(card, 2) != 0x01 ||
+ ems_pci_v1_readb(card, 3) != 0xCB ||
+ ems_pci_v1_readb(card, 4) != 0x11) {
+ dev_err(&pdev->dev,
+ "Not EMS Dr. Thomas Wuensche interface\n");
+ err = -ENODEV;
+ goto failure_cleanup;
+ }
}
ems_pci_card_reset(card);
/* Detect available channels */
- for (i = 0; i < EMS_PCI_MAX_CHAN; i++) {
+ for (i = 0; i < max_chan; i++) {
dev = alloc_sja1000dev(0);
if (dev == NULL) {
err = -ENOMEM;
@@ -255,20 +307,32 @@ static int __devinit ems_pci_add_card(struct pci_dev *pdev,
dev->irq = pdev->irq;
priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
+ (i * EMS_PCI_CAN_CTRL_SIZE);
+ if (card->version == 1) {
+ priv->read_reg = ems_pci_v1_read_reg;
+ priv->write_reg = ems_pci_v1_write_reg;
+ priv->post_irq = ems_pci_v1_post_irq;
+ } else {
+ priv->read_reg = ems_pci_v2_read_reg;
+ priv->write_reg = ems_pci_v2_write_reg;
+ priv->post_irq = ems_pci_v2_post_irq;
+ }
/* Check if channel is present */
if (ems_pci_check_chan(priv)) {
- priv->read_reg = ems_pci_read_reg;
- priv->write_reg = ems_pci_write_reg;
- priv->post_irq = ems_pci_post_irq;
priv->can.clock.freq = EMS_PCI_CAN_CLOCK;
priv->ocr = EMS_PCI_OCR;
priv->cdr = EMS_PCI_CDR;
SET_NETDEV_DEV(dev, &pdev->dev);
- /* Enable interrupts from card */
- writel(PITA2_ICR_INT0_EN, card->conf_addr + PITA2_ICR);
+ if (card->version == 1)
+ /* reset int flag of pita */
+ writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
+ card->conf_addr + PITA2_ICR);
+ else
+ /* enable IRQ in PLX 9030 */
+ writel(PLX_ICSR_ENA_CLR,
+ card->conf_addr + PLX_ICSR);
/* Register SJA1000 device */
err = register_sja1000dev(dev);
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 08ebee79d8a..b3004de1e5e 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -282,7 +282,7 @@ static int sja1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
priv->write_reg(priv, REG_CMR, CMD_TR);
- return 0;
+ return NETDEV_TX_OK;
}
static void sja1000_rx(struct net_device *dev)
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index eb066673c2a..299a33b914f 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2928,7 +2928,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
static int ring;
if (skb_padto(skb, cp->min_frame_size))
- return 0;
+ return NETDEV_TX_OK;
/* XXX: we need some higher-level QoS hooks to steer packets to
* individual queues.
@@ -2936,7 +2936,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (cas_xmit_tx_ringN(cp, ring++ & N_TX_RINGS_MASK, skb))
return NETDEV_TX_BUSY;
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void cas_init_tx_dma(struct cas *cp)
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 7a18dc7e5c7..15c0195ebd3 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -1108,7 +1108,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&np->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 55445f980f9..ecf88abbf99 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -1367,7 +1367,7 @@ net_open(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
disable_dma(dev->dma);
clear_dma_ff(dev->dma);
- set_dma_mode(dev->dma, 0x14); /* auto_init as well */
+ set_dma_mode(dev->dma, DMA_RX_MODE); /* auto_init as well */
set_dma_addr(dev->dma, isa_virt_to_bus(lp->dma_buff));
set_dma_count(dev->dma, lp->dmasize*1024);
enable_dma(dev->dma);
@@ -1572,7 +1572,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
* to restart the netdevice layer
*/
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 1694fad3872..74723f2e743 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -276,6 +276,14 @@ static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
return netdev_priv(adap->port[idx]);
}
+static inline int phy2portid(struct cphy *phy)
+{
+ struct adapter *adap = phy->adapter;
+ struct port_info *port0 = adap2pinfo(adap, 0);
+
+ return &port0->phy == phy ? 0 : 1;
+}
+
#define OFFLOAD_DEVMAP_BIT 15
#define tdev2adap(d) container_of(d, struct adapter, tdev)
@@ -312,4 +320,6 @@ int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
unsigned char *data);
irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size);
+
#endif /* __T3_ADAPTER_H__ */
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
index 9fe008ec9ba..5248f9e0b2f 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/cxgb3/ael1002.c
@@ -224,12 +224,6 @@ static int ael1006_reset(struct cphy *phy, int wait)
return t3_phy_reset(phy, MDIO_MMD_PMAPMD, wait);
}
-static int ael1006_power_down(struct cphy *phy, int enable)
-{
- return mdio_set_flag(&phy->mdio, phy->mdio.prtad, MDIO_MMD_PMAPMD,
- MDIO_CTRL1, MDIO_CTRL1_LPOWER, enable);
-}
-
static struct cphy_ops ael1006_ops = {
.reset = ael1006_reset,
.intr_enable = t3_phy_lasi_intr_enable,
@@ -237,7 +231,7 @@ static struct cphy_ops ael1006_ops = {
.intr_clear = t3_phy_lasi_intr_clear,
.intr_handler = t3_phy_lasi_intr_handler,
.get_link_status = get_link_status_r,
- .power_down = ael1006_power_down,
+ .power_down = ael1002_power_down,
.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
};
@@ -304,279 +298,7 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
{ MDIO_MMD_PMAPMD, 0xc04a, 0xffff, 0x5200 },
{ 0, 0, 0, 0 }
};
- static u16 sr_edc[] = {
- 0xcc00, 0x2ff4,
- 0xcc01, 0x3cd4,
- 0xcc02, 0x2015,
- 0xcc03, 0x3105,
- 0xcc04, 0x6524,
- 0xcc05, 0x27ff,
- 0xcc06, 0x300f,
- 0xcc07, 0x2c8b,
- 0xcc08, 0x300b,
- 0xcc09, 0x4009,
- 0xcc0a, 0x400e,
- 0xcc0b, 0x2f72,
- 0xcc0c, 0x3002,
- 0xcc0d, 0x1002,
- 0xcc0e, 0x2172,
- 0xcc0f, 0x3012,
- 0xcc10, 0x1002,
- 0xcc11, 0x25d2,
- 0xcc12, 0x3012,
- 0xcc13, 0x1002,
- 0xcc14, 0xd01e,
- 0xcc15, 0x27d2,
- 0xcc16, 0x3012,
- 0xcc17, 0x1002,
- 0xcc18, 0x2004,
- 0xcc19, 0x3c84,
- 0xcc1a, 0x6436,
- 0xcc1b, 0x2007,
- 0xcc1c, 0x3f87,
- 0xcc1d, 0x8676,
- 0xcc1e, 0x40b7,
- 0xcc1f, 0xa746,
- 0xcc20, 0x4047,
- 0xcc21, 0x5673,
- 0xcc22, 0x2982,
- 0xcc23, 0x3002,
- 0xcc24, 0x13d2,
- 0xcc25, 0x8bbd,
- 0xcc26, 0x2862,
- 0xcc27, 0x3012,
- 0xcc28, 0x1002,
- 0xcc29, 0x2092,
- 0xcc2a, 0x3012,
- 0xcc2b, 0x1002,
- 0xcc2c, 0x5cc3,
- 0xcc2d, 0x314,
- 0xcc2e, 0x2942,
- 0xcc2f, 0x3002,
- 0xcc30, 0x1002,
- 0xcc31, 0xd019,
- 0xcc32, 0x2032,
- 0xcc33, 0x3012,
- 0xcc34, 0x1002,
- 0xcc35, 0x2a04,
- 0xcc36, 0x3c74,
- 0xcc37, 0x6435,
- 0xcc38, 0x2fa4,
- 0xcc39, 0x3cd4,
- 0xcc3a, 0x6624,
- 0xcc3b, 0x5563,
- 0xcc3c, 0x2d42,
- 0xcc3d, 0x3002,
- 0xcc3e, 0x13d2,
- 0xcc3f, 0x464d,
- 0xcc40, 0x2862,
- 0xcc41, 0x3012,
- 0xcc42, 0x1002,
- 0xcc43, 0x2032,
- 0xcc44, 0x3012,
- 0xcc45, 0x1002,
- 0xcc46, 0x2fb4,
- 0xcc47, 0x3cd4,
- 0xcc48, 0x6624,
- 0xcc49, 0x5563,
- 0xcc4a, 0x2d42,
- 0xcc4b, 0x3002,
- 0xcc4c, 0x13d2,
- 0xcc4d, 0x2ed2,
- 0xcc4e, 0x3002,
- 0xcc4f, 0x1002,
- 0xcc50, 0x2fd2,
- 0xcc51, 0x3002,
- 0xcc52, 0x1002,
- 0xcc53, 0x004,
- 0xcc54, 0x2942,
- 0xcc55, 0x3002,
- 0xcc56, 0x1002,
- 0xcc57, 0x2092,
- 0xcc58, 0x3012,
- 0xcc59, 0x1002,
- 0xcc5a, 0x5cc3,
- 0xcc5b, 0x317,
- 0xcc5c, 0x2f72,
- 0xcc5d, 0x3002,
- 0xcc5e, 0x1002,
- 0xcc5f, 0x2942,
- 0xcc60, 0x3002,
- 0xcc61, 0x1002,
- 0xcc62, 0x22cd,
- 0xcc63, 0x301d,
- 0xcc64, 0x2862,
- 0xcc65, 0x3012,
- 0xcc66, 0x1002,
- 0xcc67, 0x2ed2,
- 0xcc68, 0x3002,
- 0xcc69, 0x1002,
- 0xcc6a, 0x2d72,
- 0xcc6b, 0x3002,
- 0xcc6c, 0x1002,
- 0xcc6d, 0x628f,
- 0xcc6e, 0x2112,
- 0xcc6f, 0x3012,
- 0xcc70, 0x1002,
- 0xcc71, 0x5aa3,
- 0xcc72, 0x2dc2,
- 0xcc73, 0x3002,
- 0xcc74, 0x1312,
- 0xcc75, 0x6f72,
- 0xcc76, 0x1002,
- 0xcc77, 0x2807,
- 0xcc78, 0x31a7,
- 0xcc79, 0x20c4,
- 0xcc7a, 0x3c24,
- 0xcc7b, 0x6724,
- 0xcc7c, 0x1002,
- 0xcc7d, 0x2807,
- 0xcc7e, 0x3187,
- 0xcc7f, 0x20c4,
- 0xcc80, 0x3c24,
- 0xcc81, 0x6724,
- 0xcc82, 0x1002,
- 0xcc83, 0x2514,
- 0xcc84, 0x3c64,
- 0xcc85, 0x6436,
- 0xcc86, 0xdff4,
- 0xcc87, 0x6436,
- 0xcc88, 0x1002,
- 0xcc89, 0x40a4,
- 0xcc8a, 0x643c,
- 0xcc8b, 0x4016,
- 0xcc8c, 0x8c6c,
- 0xcc8d, 0x2b24,
- 0xcc8e, 0x3c24,
- 0xcc8f, 0x6435,
- 0xcc90, 0x1002,
- 0xcc91, 0x2b24,
- 0xcc92, 0x3c24,
- 0xcc93, 0x643a,
- 0xcc94, 0x4025,
- 0xcc95, 0x8a5a,
- 0xcc96, 0x1002,
- 0xcc97, 0x2731,
- 0xcc98, 0x3011,
- 0xcc99, 0x1001,
- 0xcc9a, 0xc7a0,
- 0xcc9b, 0x100,
- 0xcc9c, 0xc502,
- 0xcc9d, 0x53ac,
- 0xcc9e, 0xc503,
- 0xcc9f, 0xd5d5,
- 0xcca0, 0xc600,
- 0xcca1, 0x2a6d,
- 0xcca2, 0xc601,
- 0xcca3, 0x2a4c,
- 0xcca4, 0xc602,
- 0xcca5, 0x111,
- 0xcca6, 0xc60c,
- 0xcca7, 0x5900,
- 0xcca8, 0xc710,
- 0xcca9, 0x700,
- 0xccaa, 0xc718,
- 0xccab, 0x700,
- 0xccac, 0xc720,
- 0xccad, 0x4700,
- 0xccae, 0xc801,
- 0xccaf, 0x7f50,
- 0xccb0, 0xc802,
- 0xccb1, 0x7760,
- 0xccb2, 0xc803,
- 0xccb3, 0x7fce,
- 0xccb4, 0xc804,
- 0xccb5, 0x5700,
- 0xccb6, 0xc805,
- 0xccb7, 0x5f11,
- 0xccb8, 0xc806,
- 0xccb9, 0x4751,
- 0xccba, 0xc807,
- 0xccbb, 0x57e1,
- 0xccbc, 0xc808,
- 0xccbd, 0x2700,
- 0xccbe, 0xc809,
- 0xccbf, 0x000,
- 0xccc0, 0xc821,
- 0xccc1, 0x002,
- 0xccc2, 0xc822,
- 0xccc3, 0x014,
- 0xccc4, 0xc832,
- 0xccc5, 0x1186,
- 0xccc6, 0xc847,
- 0xccc7, 0x1e02,
- 0xccc8, 0xc013,
- 0xccc9, 0xf341,
- 0xccca, 0xc01a,
- 0xcccb, 0x446,
- 0xcccc, 0xc024,
- 0xcccd, 0x1000,
- 0xccce, 0xc025,
- 0xcccf, 0xa00,
- 0xccd0, 0xc026,
- 0xccd1, 0xc0c,
- 0xccd2, 0xc027,
- 0xccd3, 0xc0c,
- 0xccd4, 0xc029,
- 0xccd5, 0x0a0,
- 0xccd6, 0xc030,
- 0xccd7, 0xa00,
- 0xccd8, 0xc03c,
- 0xccd9, 0x01c,
- 0xccda, 0xc005,
- 0xccdb, 0x7a06,
- 0xccdc, 0x000,
- 0xccdd, 0x2731,
- 0xccde, 0x3011,
- 0xccdf, 0x1001,
- 0xcce0, 0xc620,
- 0xcce1, 0x000,
- 0xcce2, 0xc621,
- 0xcce3, 0x03f,
- 0xcce4, 0xc622,
- 0xcce5, 0x000,
- 0xcce6, 0xc623,
- 0xcce7, 0x000,
- 0xcce8, 0xc624,
- 0xcce9, 0x000,
- 0xccea, 0xc625,
- 0xcceb, 0x000,
- 0xccec, 0xc627,
- 0xcced, 0x000,
- 0xccee, 0xc628,
- 0xccef, 0x000,
- 0xccf0, 0xc62c,
- 0xccf1, 0x000,
- 0xccf2, 0x000,
- 0xccf3, 0x2806,
- 0xccf4, 0x3cb6,
- 0xccf5, 0xc161,
- 0xccf6, 0x6134,
- 0xccf7, 0x6135,
- 0xccf8, 0x5443,
- 0xccf9, 0x303,
- 0xccfa, 0x6524,
- 0xccfb, 0x00b,
- 0xccfc, 0x1002,
- 0xccfd, 0x2104,
- 0xccfe, 0x3c24,
- 0xccff, 0x2105,
- 0xcd00, 0x3805,
- 0xcd01, 0x6524,
- 0xcd02, 0xdff4,
- 0xcd03, 0x4005,
- 0xcd04, 0x6524,
- 0xcd05, 0x1002,
- 0xcd06, 0x5dd3,
- 0xcd07, 0x306,
- 0xcd08, 0x2ff7,
- 0xcd09, 0x38f7,
- 0xcd0a, 0x60b7,
- 0xcd0b, 0xdffd,
- 0xcd0c, 0x00a,
- 0xcd0d, 0x1002,
- 0xcd0e, 0
- };
+
int i, err;
err = set_phy_regs(phy, regs);
@@ -585,9 +307,16 @@ static int ael2005_setup_sr_edc(struct cphy *phy)
msleep(50);
- for (i = 0; i < ARRAY_SIZE(sr_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, sr_edc[i],
- sr_edc[i + 1]);
+ if (phy->priv != edc_sr)
+ err = t3_get_edc_fw(phy, EDC_OPT_AEL2005,
+ EDC_OPT_AEL2005_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_OPT_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
if (!err)
phy->priv = edc_sr;
return err;
@@ -604,374 +333,6 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
{ MDIO_MMD_PMAPMD, 0xc015, 0xffff, 0xa000 },
{ 0, 0, 0, 0 }
};
- static u16 twinax_edc[] = {
- 0xcc00, 0x4009,
- 0xcc01, 0x27ff,
- 0xcc02, 0x300f,
- 0xcc03, 0x40aa,
- 0xcc04, 0x401c,
- 0xcc05, 0x401e,
- 0xcc06, 0x2ff4,
- 0xcc07, 0x3cd4,
- 0xcc08, 0x2035,
- 0xcc09, 0x3145,
- 0xcc0a, 0x6524,
- 0xcc0b, 0x26a2,
- 0xcc0c, 0x3012,
- 0xcc0d, 0x1002,
- 0xcc0e, 0x29c2,
- 0xcc0f, 0x3002,
- 0xcc10, 0x1002,
- 0xcc11, 0x2072,
- 0xcc12, 0x3012,
- 0xcc13, 0x1002,
- 0xcc14, 0x22cd,
- 0xcc15, 0x301d,
- 0xcc16, 0x2e52,
- 0xcc17, 0x3012,
- 0xcc18, 0x1002,
- 0xcc19, 0x28e2,
- 0xcc1a, 0x3002,
- 0xcc1b, 0x1002,
- 0xcc1c, 0x628f,
- 0xcc1d, 0x2ac2,
- 0xcc1e, 0x3012,
- 0xcc1f, 0x1002,
- 0xcc20, 0x5553,
- 0xcc21, 0x2ae2,
- 0xcc22, 0x3002,
- 0xcc23, 0x1302,
- 0xcc24, 0x401e,
- 0xcc25, 0x2be2,
- 0xcc26, 0x3012,
- 0xcc27, 0x1002,
- 0xcc28, 0x2da2,
- 0xcc29, 0x3012,
- 0xcc2a, 0x1002,
- 0xcc2b, 0x2ba2,
- 0xcc2c, 0x3002,
- 0xcc2d, 0x1002,
- 0xcc2e, 0x5ee3,
- 0xcc2f, 0x305,
- 0xcc30, 0x400e,
- 0xcc31, 0x2bc2,
- 0xcc32, 0x3002,
- 0xcc33, 0x1002,
- 0xcc34, 0x2b82,
- 0xcc35, 0x3012,
- 0xcc36, 0x1002,
- 0xcc37, 0x5663,
- 0xcc38, 0x302,
- 0xcc39, 0x401e,
- 0xcc3a, 0x6f72,
- 0xcc3b, 0x1002,
- 0xcc3c, 0x628f,
- 0xcc3d, 0x2be2,
- 0xcc3e, 0x3012,
- 0xcc3f, 0x1002,
- 0xcc40, 0x22cd,
- 0xcc41, 0x301d,
- 0xcc42, 0x2e52,
- 0xcc43, 0x3012,
- 0xcc44, 0x1002,
- 0xcc45, 0x2522,
- 0xcc46, 0x3012,
- 0xcc47, 0x1002,
- 0xcc48, 0x2da2,
- 0xcc49, 0x3012,
- 0xcc4a, 0x1002,
- 0xcc4b, 0x2ca2,
- 0xcc4c, 0x3012,
- 0xcc4d, 0x1002,
- 0xcc4e, 0x2fa4,
- 0xcc4f, 0x3cd4,
- 0xcc50, 0x6624,
- 0xcc51, 0x410b,
- 0xcc52, 0x56b3,
- 0xcc53, 0x3c4,
- 0xcc54, 0x2fb2,
- 0xcc55, 0x3002,
- 0xcc56, 0x1002,
- 0xcc57, 0x220b,
- 0xcc58, 0x303b,
- 0xcc59, 0x56b3,
- 0xcc5a, 0x3c3,
- 0xcc5b, 0x866b,
- 0xcc5c, 0x400c,
- 0xcc5d, 0x23a2,
- 0xcc5e, 0x3012,
- 0xcc5f, 0x1002,
- 0xcc60, 0x2da2,
- 0xcc61, 0x3012,
- 0xcc62, 0x1002,
- 0xcc63, 0x2ca2,
- 0xcc64, 0x3012,
- 0xcc65, 0x1002,
- 0xcc66, 0x2fb4,
- 0xcc67, 0x3cd4,
- 0xcc68, 0x6624,
- 0xcc69, 0x56b3,
- 0xcc6a, 0x3c3,
- 0xcc6b, 0x866b,
- 0xcc6c, 0x401c,
- 0xcc6d, 0x2205,
- 0xcc6e, 0x3035,
- 0xcc6f, 0x5b53,
- 0xcc70, 0x2c52,
- 0xcc71, 0x3002,
- 0xcc72, 0x13c2,
- 0xcc73, 0x5cc3,
- 0xcc74, 0x317,
- 0xcc75, 0x2522,
- 0xcc76, 0x3012,
- 0xcc77, 0x1002,
- 0xcc78, 0x2da2,
- 0xcc79, 0x3012,
- 0xcc7a, 0x1002,
- 0xcc7b, 0x2b82,
- 0xcc7c, 0x3012,
- 0xcc7d, 0x1002,
- 0xcc7e, 0x5663,
- 0xcc7f, 0x303,
- 0xcc80, 0x401e,
- 0xcc81, 0x004,
- 0xcc82, 0x2c42,
- 0xcc83, 0x3012,
- 0xcc84, 0x1002,
- 0xcc85, 0x6f72,
- 0xcc86, 0x1002,
- 0xcc87, 0x628f,
- 0xcc88, 0x2304,
- 0xcc89, 0x3c84,
- 0xcc8a, 0x6436,
- 0xcc8b, 0xdff4,
- 0xcc8c, 0x6436,
- 0xcc8d, 0x2ff5,
- 0xcc8e, 0x3005,
- 0xcc8f, 0x8656,
- 0xcc90, 0xdfba,
- 0xcc91, 0x56a3,
- 0xcc92, 0xd05a,
- 0xcc93, 0x21c2,
- 0xcc94, 0x3012,
- 0xcc95, 0x1392,
- 0xcc96, 0xd05a,
- 0xcc97, 0x56a3,
- 0xcc98, 0xdfba,
- 0xcc99, 0x383,
- 0xcc9a, 0x6f72,
- 0xcc9b, 0x1002,
- 0xcc9c, 0x28c5,
- 0xcc9d, 0x3005,
- 0xcc9e, 0x4178,
- 0xcc9f, 0x5653,
- 0xcca0, 0x384,
- 0xcca1, 0x22b2,
- 0xcca2, 0x3012,
- 0xcca3, 0x1002,
- 0xcca4, 0x2be5,
- 0xcca5, 0x3005,
- 0xcca6, 0x41e8,
- 0xcca7, 0x5653,
- 0xcca8, 0x382,
- 0xcca9, 0x002,
- 0xccaa, 0x4258,
- 0xccab, 0x2474,
- 0xccac, 0x3c84,
- 0xccad, 0x6437,
- 0xccae, 0xdff4,
- 0xccaf, 0x6437,
- 0xccb0, 0x2ff5,
- 0xccb1, 0x3c05,
- 0xccb2, 0x8757,
- 0xccb3, 0xb888,
- 0xccb4, 0x9787,
- 0xccb5, 0xdff4,
- 0xccb6, 0x6724,
- 0xccb7, 0x866a,
- 0xccb8, 0x6f72,
- 0xccb9, 0x1002,
- 0xccba, 0x2d01,
- 0xccbb, 0x3011,
- 0xccbc, 0x1001,
- 0xccbd, 0xc620,
- 0xccbe, 0x14e5,
- 0xccbf, 0xc621,
- 0xccc0, 0xc53d,
- 0xccc1, 0xc622,
- 0xccc2, 0x3cbe,
- 0xccc3, 0xc623,
- 0xccc4, 0x4452,
- 0xccc5, 0xc624,
- 0xccc6, 0xc5c5,
- 0xccc7, 0xc625,
- 0xccc8, 0xe01e,
- 0xccc9, 0xc627,
- 0xccca, 0x000,
- 0xcccb, 0xc628,
- 0xcccc, 0x000,
- 0xcccd, 0xc62b,
- 0xccce, 0x000,
- 0xcccf, 0xc62c,
- 0xccd0, 0x000,
- 0xccd1, 0x000,
- 0xccd2, 0x2d01,
- 0xccd3, 0x3011,
- 0xccd4, 0x1001,
- 0xccd5, 0xc620,
- 0xccd6, 0x000,
- 0xccd7, 0xc621,
- 0xccd8, 0x000,
- 0xccd9, 0xc622,
- 0xccda, 0x0ce,
- 0xccdb, 0xc623,
- 0xccdc, 0x07f,
- 0xccdd, 0xc624,
- 0xccde, 0x032,
- 0xccdf, 0xc625,
- 0xcce0, 0x000,
- 0xcce1, 0xc627,
- 0xcce2, 0x000,
- 0xcce3, 0xc628,
- 0xcce4, 0x000,
- 0xcce5, 0xc62b,
- 0xcce6, 0x000,
- 0xcce7, 0xc62c,
- 0xcce8, 0x000,
- 0xcce9, 0x000,
- 0xccea, 0x2d01,
- 0xcceb, 0x3011,
- 0xccec, 0x1001,
- 0xcced, 0xc502,
- 0xccee, 0x609f,
- 0xccef, 0xc600,
- 0xccf0, 0x2a6e,
- 0xccf1, 0xc601,
- 0xccf2, 0x2a2c,
- 0xccf3, 0xc60c,
- 0xccf4, 0x5400,
- 0xccf5, 0xc710,
- 0xccf6, 0x700,
- 0xccf7, 0xc718,
- 0xccf8, 0x700,
- 0xccf9, 0xc720,
- 0xccfa, 0x4700,
- 0xccfb, 0xc728,
- 0xccfc, 0x700,
- 0xccfd, 0xc729,
- 0xccfe, 0x1207,
- 0xccff, 0xc801,
- 0xcd00, 0x7f50,
- 0xcd01, 0xc802,
- 0xcd02, 0x7760,
- 0xcd03, 0xc803,
- 0xcd04, 0x7fce,
- 0xcd05, 0xc804,
- 0xcd06, 0x520e,
- 0xcd07, 0xc805,
- 0xcd08, 0x5c11,
- 0xcd09, 0xc806,
- 0xcd0a, 0x3c51,
- 0xcd0b, 0xc807,
- 0xcd0c, 0x4061,
- 0xcd0d, 0xc808,
- 0xcd0e, 0x49c1,
- 0xcd0f, 0xc809,
- 0xcd10, 0x3840,
- 0xcd11, 0xc80a,
- 0xcd12, 0x000,
- 0xcd13, 0xc821,
- 0xcd14, 0x002,
- 0xcd15, 0xc822,
- 0xcd16, 0x046,
- 0xcd17, 0xc844,
- 0xcd18, 0x182f,
- 0xcd19, 0xc013,
- 0xcd1a, 0xf341,
- 0xcd1b, 0xc01a,
- 0xcd1c, 0x446,
- 0xcd1d, 0xc024,
- 0xcd1e, 0x1000,
- 0xcd1f, 0xc025,
- 0xcd20, 0xa00,
- 0xcd21, 0xc026,
- 0xcd22, 0xc0c,
- 0xcd23, 0xc027,
- 0xcd24, 0xc0c,
- 0xcd25, 0xc029,
- 0xcd26, 0x0a0,
- 0xcd27, 0xc030,
- 0xcd28, 0xa00,
- 0xcd29, 0xc03c,
- 0xcd2a, 0x01c,
- 0xcd2b, 0x000,
- 0xcd2c, 0x2b84,
- 0xcd2d, 0x3c74,
- 0xcd2e, 0x6435,
- 0xcd2f, 0xdff4,
- 0xcd30, 0x6435,
- 0xcd31, 0x2806,
- 0xcd32, 0x3006,
- 0xcd33, 0x8565,
- 0xcd34, 0x2b24,
- 0xcd35, 0x3c24,
- 0xcd36, 0x6436,
- 0xcd37, 0x1002,
- 0xcd38, 0x2b24,
- 0xcd39, 0x3c24,
- 0xcd3a, 0x6436,
- 0xcd3b, 0x4045,
- 0xcd3c, 0x8656,
- 0xcd3d, 0x1002,
- 0xcd3e, 0x2807,
- 0xcd3f, 0x31a7,
- 0xcd40, 0x20c4,
- 0xcd41, 0x3c24,
- 0xcd42, 0x6724,
- 0xcd43, 0x1002,
- 0xcd44, 0x2807,
- 0xcd45, 0x3187,
- 0xcd46, 0x20c4,
- 0xcd47, 0x3c24,
- 0xcd48, 0x6724,
- 0xcd49, 0x1002,
- 0xcd4a, 0x2514,
- 0xcd4b, 0x3c64,
- 0xcd4c, 0x6436,
- 0xcd4d, 0xdff4,
- 0xcd4e, 0x6436,
- 0xcd4f, 0x1002,
- 0xcd50, 0x2806,
- 0xcd51, 0x3cb6,
- 0xcd52, 0xc161,
- 0xcd53, 0x6134,
- 0xcd54, 0x6135,
- 0xcd55, 0x5443,
- 0xcd56, 0x303,
- 0xcd57, 0x6524,
- 0xcd58, 0x00b,
- 0xcd59, 0x1002,
- 0xcd5a, 0xd019,
- 0xcd5b, 0x2104,
- 0xcd5c, 0x3c24,
- 0xcd5d, 0x2105,
- 0xcd5e, 0x3805,
- 0xcd5f, 0x6524,
- 0xcd60, 0xdff4,
- 0xcd61, 0x4005,
- 0xcd62, 0x6524,
- 0xcd63, 0x2e8d,
- 0xcd64, 0x303d,
- 0xcd65, 0x5dd3,
- 0xcd66, 0x306,
- 0xcd67, 0x2ff7,
- 0xcd68, 0x38f7,
- 0xcd69, 0x60b7,
- 0xcd6a, 0xdffd,
- 0xcd6b, 0x00a,
- 0xcd6c, 0x1002,
- 0xcd6d, 0
- };
int i, err;
err = set_phy_regs(phy, regs);
@@ -982,9 +343,16 @@ static int ael2005_setup_twinax_edc(struct cphy *phy, int modtype)
msleep(50);
- for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
- twinax_edc[i + 1]);
+ if (phy->priv != edc_twinax)
+ err = t3_get_edc_fw(phy, EDC_TWX_AEL2005,
+ EDC_TWX_AEL2005_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_TWX_AEL2005_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
if (!err)
phy->priv = edc_twinax;
return err;
@@ -1201,405 +569,6 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
{ MDIO_MMD_PMAPMD, 0xd092, 0xffff, 0x0000 },
{ 0, 0, 0, 0 }
};
-
- /* TWINAX EDC firmware */
- static u16 twinax_edc[] = {
- 0xd800, 0x4009,
- 0xd801, 0x2fff,
- 0xd802, 0x300f,
- 0xd803, 0x40aa,
- 0xd804, 0x401c,
- 0xd805, 0x401e,
- 0xd806, 0x2ff4,
- 0xd807, 0x3dc4,
- 0xd808, 0x2035,
- 0xd809, 0x3035,
- 0xd80a, 0x6524,
- 0xd80b, 0x2cb2,
- 0xd80c, 0x3012,
- 0xd80d, 0x1002,
- 0xd80e, 0x26e2,
- 0xd80f, 0x3022,
- 0xd810, 0x1002,
- 0xd811, 0x27d2,
- 0xd812, 0x3022,
- 0xd813, 0x1002,
- 0xd814, 0x2822,
- 0xd815, 0x3012,
- 0xd816, 0x1002,
- 0xd817, 0x2492,
- 0xd818, 0x3022,
- 0xd819, 0x1002,
- 0xd81a, 0x2772,
- 0xd81b, 0x3012,
- 0xd81c, 0x1002,
- 0xd81d, 0x23d2,
- 0xd81e, 0x3022,
- 0xd81f, 0x1002,
- 0xd820, 0x22cd,
- 0xd821, 0x301d,
- 0xd822, 0x27f2,
- 0xd823, 0x3022,
- 0xd824, 0x1002,
- 0xd825, 0x5553,
- 0xd826, 0x0307,
- 0xd827, 0x2522,
- 0xd828, 0x3022,
- 0xd829, 0x1002,
- 0xd82a, 0x2142,
- 0xd82b, 0x3012,
- 0xd82c, 0x1002,
- 0xd82d, 0x4016,
- 0xd82e, 0x5e63,
- 0xd82f, 0x0344,
- 0xd830, 0x2142,
- 0xd831, 0x3012,
- 0xd832, 0x1002,
- 0xd833, 0x400e,
- 0xd834, 0x2522,
- 0xd835, 0x3022,
- 0xd836, 0x1002,
- 0xd837, 0x2b52,
- 0xd838, 0x3012,
- 0xd839, 0x1002,
- 0xd83a, 0x2742,
- 0xd83b, 0x3022,
- 0xd83c, 0x1002,
- 0xd83d, 0x25e2,
- 0xd83e, 0x3022,
- 0xd83f, 0x1002,
- 0xd840, 0x2fa4,
- 0xd841, 0x3dc4,
- 0xd842, 0x6624,
- 0xd843, 0x414b,
- 0xd844, 0x56b3,
- 0xd845, 0x03c6,
- 0xd846, 0x866b,
- 0xd847, 0x400c,
- 0xd848, 0x2712,
- 0xd849, 0x3012,
- 0xd84a, 0x1002,
- 0xd84b, 0x2c4b,
- 0xd84c, 0x309b,
- 0xd84d, 0x56b3,
- 0xd84e, 0x03c3,
- 0xd84f, 0x866b,
- 0xd850, 0x400c,
- 0xd851, 0x2272,
- 0xd852, 0x3022,
- 0xd853, 0x1002,
- 0xd854, 0x2742,
- 0xd855, 0x3022,
- 0xd856, 0x1002,
- 0xd857, 0x25e2,
- 0xd858, 0x3022,
- 0xd859, 0x1002,
- 0xd85a, 0x2fb4,
- 0xd85b, 0x3dc4,
- 0xd85c, 0x6624,
- 0xd85d, 0x56b3,
- 0xd85e, 0x03c3,
- 0xd85f, 0x866b,
- 0xd860, 0x401c,
- 0xd861, 0x2c45,
- 0xd862, 0x3095,
- 0xd863, 0x5b53,
- 0xd864, 0x2372,
- 0xd865, 0x3012,
- 0xd866, 0x13c2,
- 0xd867, 0x5cc3,
- 0xd868, 0x2712,
- 0xd869, 0x3012,
- 0xd86a, 0x1312,
- 0xd86b, 0x2b52,
- 0xd86c, 0x3012,
- 0xd86d, 0x1002,
- 0xd86e, 0x2742,
- 0xd86f, 0x3022,
- 0xd870, 0x1002,
- 0xd871, 0x2582,
- 0xd872, 0x3022,
- 0xd873, 0x1002,
- 0xd874, 0x2142,
- 0xd875, 0x3012,
- 0xd876, 0x1002,
- 0xd877, 0x628f,
- 0xd878, 0x2985,
- 0xd879, 0x33a5,
- 0xd87a, 0x25e2,
- 0xd87b, 0x3022,
- 0xd87c, 0x1002,
- 0xd87d, 0x5653,
- 0xd87e, 0x03d2,
- 0xd87f, 0x401e,
- 0xd880, 0x6f72,
- 0xd881, 0x1002,
- 0xd882, 0x628f,
- 0xd883, 0x2304,
- 0xd884, 0x3c84,
- 0xd885, 0x6436,
- 0xd886, 0xdff4,
- 0xd887, 0x6436,
- 0xd888, 0x2ff5,
- 0xd889, 0x3005,
- 0xd88a, 0x8656,
- 0xd88b, 0xdfba,
- 0xd88c, 0x56a3,
- 0xd88d, 0xd05a,
- 0xd88e, 0x2972,
- 0xd88f, 0x3012,
- 0xd890, 0x1392,
- 0xd891, 0xd05a,
- 0xd892, 0x56a3,
- 0xd893, 0xdfba,
- 0xd894, 0x0383,
- 0xd895, 0x6f72,
- 0xd896, 0x1002,
- 0xd897, 0x2b45,
- 0xd898, 0x3005,
- 0xd899, 0x4178,
- 0xd89a, 0x5653,
- 0xd89b, 0x0384,
- 0xd89c, 0x2a62,
- 0xd89d, 0x3012,
- 0xd89e, 0x1002,
- 0xd89f, 0x2f05,
- 0xd8a0, 0x3005,
- 0xd8a1, 0x41c8,
- 0xd8a2, 0x5653,
- 0xd8a3, 0x0382,
- 0xd8a4, 0x0002,
- 0xd8a5, 0x4218,
- 0xd8a6, 0x2474,
- 0xd8a7, 0x3c84,
- 0xd8a8, 0x6437,
- 0xd8a9, 0xdff4,
- 0xd8aa, 0x6437,
- 0xd8ab, 0x2ff5,
- 0xd8ac, 0x3c05,
- 0xd8ad, 0x8757,
- 0xd8ae, 0xb888,
- 0xd8af, 0x9787,
- 0xd8b0, 0xdff4,
- 0xd8b1, 0x6724,
- 0xd8b2, 0x866a,
- 0xd8b3, 0x6f72,
- 0xd8b4, 0x1002,
- 0xd8b5, 0x2641,
- 0xd8b6, 0x3021,
- 0xd8b7, 0x1001,
- 0xd8b8, 0xc620,
- 0xd8b9, 0x0000,
- 0xd8ba, 0xc621,
- 0xd8bb, 0x0000,
- 0xd8bc, 0xc622,
- 0xd8bd, 0x00ce,
- 0xd8be, 0xc623,
- 0xd8bf, 0x007f,
- 0xd8c0, 0xc624,
- 0xd8c1, 0x0032,
- 0xd8c2, 0xc625,
- 0xd8c3, 0x0000,
- 0xd8c4, 0xc627,
- 0xd8c5, 0x0000,
- 0xd8c6, 0xc628,
- 0xd8c7, 0x0000,
- 0xd8c8, 0xc62c,
- 0xd8c9, 0x0000,
- 0xd8ca, 0x0000,
- 0xd8cb, 0x2641,
- 0xd8cc, 0x3021,
- 0xd8cd, 0x1001,
- 0xd8ce, 0xc502,
- 0xd8cf, 0x53ac,
- 0xd8d0, 0xc503,
- 0xd8d1, 0x2cd3,
- 0xd8d2, 0xc600,
- 0xd8d3, 0x2a6e,
- 0xd8d4, 0xc601,
- 0xd8d5, 0x2a2c,
- 0xd8d6, 0xc605,
- 0xd8d7, 0x5557,
- 0xd8d8, 0xc60c,
- 0xd8d9, 0x5400,
- 0xd8da, 0xc710,
- 0xd8db, 0x0700,
- 0xd8dc, 0xc711,
- 0xd8dd, 0x0f06,
- 0xd8de, 0xc718,
- 0xd8df, 0x0700,
- 0xd8e0, 0xc719,
- 0xd8e1, 0x0f06,
- 0xd8e2, 0xc720,
- 0xd8e3, 0x4700,
- 0xd8e4, 0xc721,
- 0xd8e5, 0x0f06,
- 0xd8e6, 0xc728,
- 0xd8e7, 0x0700,
- 0xd8e8, 0xc729,
- 0xd8e9, 0x1207,
- 0xd8ea, 0xc801,
- 0xd8eb, 0x7f50,
- 0xd8ec, 0xc802,
- 0xd8ed, 0x7760,
- 0xd8ee, 0xc803,
- 0xd8ef, 0x7fce,
- 0xd8f0, 0xc804,
- 0xd8f1, 0x520e,
- 0xd8f2, 0xc805,
- 0xd8f3, 0x5c11,
- 0xd8f4, 0xc806,
- 0xd8f5, 0x3c51,
- 0xd8f6, 0xc807,
- 0xd8f7, 0x4061,
- 0xd8f8, 0xc808,
- 0xd8f9, 0x49c1,
- 0xd8fa, 0xc809,
- 0xd8fb, 0x3840,
- 0xd8fc, 0xc80a,
- 0xd8fd, 0x0000,
- 0xd8fe, 0xc821,
- 0xd8ff, 0x0002,
- 0xd900, 0xc822,
- 0xd901, 0x0046,
- 0xd902, 0xc844,
- 0xd903, 0x182f,
- 0xd904, 0xc013,
- 0xd905, 0xf341,
- 0xd906, 0xc084,
- 0xd907, 0x0030,
- 0xd908, 0xc904,
- 0xd909, 0x1401,
- 0xd90a, 0xcb0c,
- 0xd90b, 0x0004,
- 0xd90c, 0xcb0e,
- 0xd90d, 0xa00a,
- 0xd90e, 0xcb0f,
- 0xd90f, 0xc0c0,
- 0xd910, 0xcb10,
- 0xd911, 0xc0c0,
- 0xd912, 0xcb11,
- 0xd913, 0x00a0,
- 0xd914, 0xcb12,
- 0xd915, 0x0007,
- 0xd916, 0xc241,
- 0xd917, 0xa000,
- 0xd918, 0xc243,
- 0xd919, 0x7fe0,
- 0xd91a, 0xc604,
- 0xd91b, 0x000e,
- 0xd91c, 0xc609,
- 0xd91d, 0x00f5,
- 0xd91e, 0xc611,
- 0xd91f, 0x000e,
- 0xd920, 0xc660,
- 0xd921, 0x9600,
- 0xd922, 0xc687,
- 0xd923, 0x0004,
- 0xd924, 0xc60a,
- 0xd925, 0x04f5,
- 0xd926, 0x0000,
- 0xd927, 0x2641,
- 0xd928, 0x3021,
- 0xd929, 0x1001,
- 0xd92a, 0xc620,
- 0xd92b, 0x14e5,
- 0xd92c, 0xc621,
- 0xd92d, 0xc53d,
- 0xd92e, 0xc622,
- 0xd92f, 0x3cbe,
- 0xd930, 0xc623,
- 0xd931, 0x4452,
- 0xd932, 0xc624,
- 0xd933, 0xc5c5,
- 0xd934, 0xc625,
- 0xd935, 0xe01e,
- 0xd936, 0xc627,
- 0xd937, 0x0000,
- 0xd938, 0xc628,
- 0xd939, 0x0000,
- 0xd93a, 0xc62c,
- 0xd93b, 0x0000,
- 0xd93c, 0x0000,
- 0xd93d, 0x2b84,
- 0xd93e, 0x3c74,
- 0xd93f, 0x6435,
- 0xd940, 0xdff4,
- 0xd941, 0x6435,
- 0xd942, 0x2806,
- 0xd943, 0x3006,
- 0xd944, 0x8565,
- 0xd945, 0x2b24,
- 0xd946, 0x3c24,
- 0xd947, 0x6436,
- 0xd948, 0x1002,
- 0xd949, 0x2b24,
- 0xd94a, 0x3c24,
- 0xd94b, 0x6436,
- 0xd94c, 0x4045,
- 0xd94d, 0x8656,
- 0xd94e, 0x5663,
- 0xd94f, 0x0302,
- 0xd950, 0x401e,
- 0xd951, 0x1002,
- 0xd952, 0x2807,
- 0xd953, 0x31a7,
- 0xd954, 0x20c4,
- 0xd955, 0x3c24,
- 0xd956, 0x6724,
- 0xd957, 0x1002,
- 0xd958, 0x2807,
- 0xd959, 0x3187,
- 0xd95a, 0x20c4,
- 0xd95b, 0x3c24,
- 0xd95c, 0x6724,
- 0xd95d, 0x1002,
- 0xd95e, 0x24f4,
- 0xd95f, 0x3c64,
- 0xd960, 0x6436,
- 0xd961, 0xdff4,
- 0xd962, 0x6436,
- 0xd963, 0x1002,
- 0xd964, 0x2006,
- 0xd965, 0x3d76,
- 0xd966, 0xc161,
- 0xd967, 0x6134,
- 0xd968, 0x6135,
- 0xd969, 0x5443,
- 0xd96a, 0x0303,
- 0xd96b, 0x6524,
- 0xd96c, 0x00fb,
- 0xd96d, 0x1002,
- 0xd96e, 0x20d4,
- 0xd96f, 0x3c24,
- 0xd970, 0x2025,
- 0xd971, 0x3005,
- 0xd972, 0x6524,
- 0xd973, 0x1002,
- 0xd974, 0xd019,
- 0xd975, 0x2104,
- 0xd976, 0x3c24,
- 0xd977, 0x2105,
- 0xd978, 0x3805,
- 0xd979, 0x6524,
- 0xd97a, 0xdff4,
- 0xd97b, 0x4005,
- 0xd97c, 0x6524,
- 0xd97d, 0x2e8d,
- 0xd97e, 0x303d,
- 0xd97f, 0x2408,
- 0xd980, 0x35d8,
- 0xd981, 0x5dd3,
- 0xd982, 0x0307,
- 0xd983, 0x8887,
- 0xd984, 0x63a7,
- 0xd985, 0x8887,
- 0xd986, 0x63a7,
- 0xd987, 0xdffd,
- 0xd988, 0x00f9,
- 0xd989, 0x1002,
- 0xd98a, 0x0000,
- };
int i, err;
/* set uC clock and activate it */
@@ -1612,10 +581,16 @@ static int ael2020_setup_twinax_edc(struct cphy *phy, int modtype)
if (err)
return err;
- /* write TWINAX EDC firmware into PHY */
- for (i = 0; i < ARRAY_SIZE(twinax_edc) && !err; i += 2)
- err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, twinax_edc[i],
- twinax_edc[i + 1]);
+ if (phy->priv != edc_twinax)
+ err = t3_get_edc_fw(phy, EDC_TWX_AEL2020,
+ EDC_TWX_AEL2020_SIZE);
+ if (err)
+ return err;
+
+ for (i = 0; i < EDC_TWX_AEL2020_SIZE / sizeof(u16) && !err; i += 2)
+ err = t3_mdio_write(phy, MDIO_MMD_PMAPMD,
+ phy->phy_cache[i],
+ phy->phy_cache[i + 1]);
/* activate uC */
err = set_phy_regs(phy, uCactivate);
if (!err)
@@ -1649,9 +624,39 @@ static int ael2020_get_module_type(struct cphy *phy, int delay_ms)
*/
static int ael2020_intr_enable(struct cphy *phy)
{
- int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0x2 << (AEL2020_GPIO_MODDET*4));
- return err ? err : t3_phy_lasi_intr_enable(phy);
+ struct reg_val regs[] = {
+ /* output Module's Loss Of Signal (LOS) to LED */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
+ 0xffff, 0x4 },
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
+
+ /* enable module detect status change interrupts */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x2 << (AEL2020_GPIO_MODDET*4) },
+
+ /* end */
+ { 0, 0, 0, 0 }
+ };
+ int err, link_ok = 0;
+
+ /* set up "link status" LED and enable module change interrupts */
+ err = set_phy_regs(phy, regs);
+ if (err)
+ return err;
+
+ err = get_link_status_r(phy, &link_ok, NULL, NULL, NULL);
+ if (err)
+ return err;
+ if (link_ok)
+ t3_link_changed(phy->adapter,
+ phy2portid(phy));
+
+ err = t3_phy_lasi_intr_enable(phy);
+ if (err)
+ return err;
+
+ return 0;
}
/*
@@ -1659,9 +664,26 @@ static int ael2020_intr_enable(struct cphy *phy)
*/
static int ael2020_intr_disable(struct cphy *phy)
{
- int err = t3_mdio_write(phy, MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0x1 << (AEL2020_GPIO_MODDET*4));
- return err ? err : t3_phy_lasi_intr_disable(phy);
+ struct reg_val regs[] = {
+ /* reset "link status" LED to "off" */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0xb << (AEL2020_GPIO_LSTAT*4) },
+
+ /* disable module detect status change interrupts */
+ { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
+ 0xffff, 0x1 << (AEL2020_GPIO_MODDET*4) },
+
+ /* end */
+ { 0, 0, 0, 0 }
+ };
+ int err;
+
+ /* turn off "link status" LED and disable module change interrupts */
+ err = set_phy_regs(phy, regs);
+ if (err)
+ return err;
+
+ return t3_phy_lasi_intr_disable(phy);
}
/*
@@ -1679,31 +701,26 @@ static int ael2020_intr_clear(struct cphy *phy)
return err ? err : t3_phy_lasi_intr_clear(phy);
}
+static struct reg_val ael2020_reset_regs[] = {
+ /* Erratum #2: CDRLOL asserted, causing PMA link down status */
+ { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
+
+ /* force XAUI to send LF when RX_LOS is asserted */
+ { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
+
+ /* allow writes to transceiver module EEPROM on i2c bus */
+ { MDIO_MMD_PMAPMD, 0xff02, 0xffff, 0x0023 },
+ { MDIO_MMD_PMAPMD, 0xff03, 0xffff, 0x0000 },
+ { MDIO_MMD_PMAPMD, 0xff04, 0xffff, 0x0000 },
+
+ /* end */
+ { 0, 0, 0, 0 }
+};
/*
* Reset the PHY and put it into a canonical operating state.
*/
static int ael2020_reset(struct cphy *phy, int wait)
{
- static struct reg_val regs0[] = {
- /* Erratum #2: CDRLOL asserted, causing PMA link down status */
- { MDIO_MMD_PMAPMD, 0xc003, 0xffff, 0x3101 },
-
- /* force XAUI to send LF when RX_LOS is asserted */
- { MDIO_MMD_PMAPMD, 0xcd40, 0xffff, 0x0001 },
-
- /* RX_LOS pin is active high */
- { MDIO_MMD_PMAPMD, AEL_OPT_SETTINGS,
- 0x0020, 0x0020 },
-
- /* output Module's Loss Of Signal (LOS) to LED */
- { MDIO_MMD_PMAPMD, AEL2020_GPIO_CFG+AEL2020_GPIO_LSTAT,
- 0xffff, 0x0004 },
- { MDIO_MMD_PMAPMD, AEL2020_GPIO_CTRL,
- 0xffff, 0x8 << (AEL2020_GPIO_LSTAT*4) },
-
- /* end */
- { 0, 0, 0, 0 }
- };
int err;
unsigned int lasi_ctrl;
@@ -1720,7 +737,7 @@ static int ael2020_reset(struct cphy *phy, int wait)
/* basic initialization for all module types */
phy->priv = edc_none;
- err = set_phy_regs(phy, regs0);
+ err = set_phy_regs(phy, ael2020_reset_regs);
if (err)
return err;
@@ -1798,10 +815,16 @@ static struct cphy_ops ael2020_ops = {
int t3_ael2020_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
const struct mdio_ops *mdio_ops)
{
+ int err;
+
cphy_init(phy, adapter, phy_addr, &ael2020_ops, mdio_ops,
SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_IRQ, "10GBASE-R");
msleep(125);
+
+ err = set_phy_regs(phy, ael2020_reset_regs);
+ if (err)
+ return err;
return 0;
}
@@ -1840,7 +863,7 @@ static struct cphy_ops qt2045_ops = {
.intr_clear = t3_phy_lasi_intr_clear,
.intr_handler = t3_phy_lasi_intr_handler,
.get_link_status = get_link_status_x,
- .power_down = ael1006_power_down,
+ .power_down = ael1002_power_down,
.mmds = MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | MDIO_DEVS_PHYXS,
};
diff --git a/drivers/net/cxgb3/aq100x.c b/drivers/net/cxgb3/aq100x.c
index b1fd5bf836e..341b7ef1508 100644
--- a/drivers/net/cxgb3/aq100x.c
+++ b/drivers/net/cxgb3/aq100x.c
@@ -271,7 +271,8 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
cphy_init(phy, adapter, phy_addr, &aq100x_ops, mdio_ops,
SUPPORTED_1000baseT_Full | SUPPORTED_10000baseT_Full |
- SUPPORTED_Autoneg | SUPPORTED_AUI, "1000/10GBASE-T");
+ SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_AUI,
+ "1000/10GBASE-T");
/*
* The PHY has been out of reset ever since the system powered up. So
@@ -316,11 +317,9 @@ int t3_aq100x_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
/* Firmware version check. */
t3_mdio_read(phy, MDIO_MMD_VEND1, AQ_FW_VERSION, &v);
- if (v != 30) {
+ if (v != 101)
CH_WARN(adapter, "PHY%d: unsupported firmware %d\n",
phy_addr, v);
- return 0; /* allow t3_prep_adapter to succeed */
- }
/*
* The PHY should start in really-low-power mode. Prepare it for normal
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index d21b705501a..1b2c305fb82 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -566,6 +566,15 @@ struct cphy_ops {
u32 mmds;
};
+enum {
+ EDC_OPT_AEL2005 = 0,
+ EDC_OPT_AEL2005_SIZE = 1084,
+ EDC_TWX_AEL2005 = 1,
+ EDC_TWX_AEL2005_SIZE = 1464,
+ EDC_TWX_AEL2020 = 2,
+ EDC_TWX_AEL2020_SIZE = 1628,
+ EDC_MAX_SIZE = EDC_TWX_AEL2020_SIZE, /* Max cache size */
+};
/* A PHY instance */
struct cphy {
@@ -577,6 +586,7 @@ struct cphy {
unsigned long fifo_errors; /* FIFO over/under-flows */
const struct cphy_ops *ops; /* PHY operations */
struct mdio_if_info mdio;
+ u16 phy_cache[EDC_MAX_SIZE]; /* EDC cache */
};
/* Convenience MDIO read/write wrappers */
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index fb5df5c6203..ec05149a906 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -172,6 +172,23 @@ static void link_report(struct net_device *dev)
}
}
+static void enable_tx_fifo_drain(struct adapter *adapter,
+ struct port_info *pi)
+{
+ t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
+ F_ENDROPPKT);
+ t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
+ t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
+ t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
+}
+
+static void disable_tx_fifo_drain(struct adapter *adapter,
+ struct port_info *pi)
+{
+ t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
+ F_ENDROPPKT, 0);
+}
+
void t3_os_link_fault(struct adapter *adap, int port_id, int state)
{
struct net_device *dev = adap->port[port_id];
@@ -185,6 +202,8 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
netif_carrier_on(dev);
+ disable_tx_fifo_drain(adap, pi);
+
/* Clear local faults */
t3_xgm_intr_disable(adap, pi->port_id);
t3_read_reg(adap, A_XGM_INT_STATUS +
@@ -200,9 +219,12 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
t3_xgm_intr_enable(adap, pi->port_id);
t3_mac_enable(mac, MAC_DIRECTION_TX);
- } else
+ } else {
netif_carrier_off(dev);
+ /* Flush TX FIFO */
+ enable_tx_fifo_drain(adap, pi);
+ }
link_report(dev);
}
@@ -232,6 +254,8 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
if (link_stat != netif_carrier_ok(dev)) {
if (link_stat) {
+ disable_tx_fifo_drain(adapter, pi);
+
t3_mac_enable(mac, MAC_DIRECTION_RX);
/* Clear local faults */
@@ -263,6 +287,9 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
t3_mac_disable(mac, MAC_DIRECTION_RX);
t3_link_start(&pi->phy, mac, &pi->link_config);
+
+ /* Flush TX FIFO */
+ enable_tx_fifo_drain(adapter, pi);
}
link_report(dev);
@@ -443,6 +470,7 @@ static int init_tp_parity(struct adapter *adap)
memset(req, 0, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
+ req->mtu_idx = NMTUS - 1;
req->iff = i;
t3_mgmt_tx(adap, skb);
if (skb == adap->nofail_skb) {
@@ -963,6 +991,75 @@ static int bind_qsets(struct adapter *adap)
#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
+#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
+#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
+#define AEL2020_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
+
+static inline const char *get_edc_fw_name(int edc_idx)
+{
+ const char *fw_name = NULL;
+
+ switch (edc_idx) {
+ case EDC_OPT_AEL2005:
+ fw_name = AEL2005_OPT_EDC_NAME;
+ break;
+ case EDC_TWX_AEL2005:
+ fw_name = AEL2005_TWX_EDC_NAME;
+ break;
+ case EDC_TWX_AEL2020:
+ fw_name = AEL2020_TWX_EDC_NAME;
+ break;
+ }
+ return fw_name;
+}
+
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
+{
+ struct adapter *adapter = phy->adapter;
+ const struct firmware *fw;
+ char buf[64];
+ u32 csum;
+ const __be32 *p;
+ u16 *cache = phy->phy_cache;
+ int i, ret;
+
+ snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
+
+ ret = request_firmware(&fw, buf, &adapter->pdev->dev);
+ if (ret < 0) {
+ dev_err(&adapter->pdev->dev,
+ "could not upgrade firmware: unable to load %s\n",
+ buf);
+ return ret;
+ }
+
+ /* check size, take checksum in account */
+ if (fw->size > size + 4) {
+ CH_ERR(adapter, "firmware image too large %u, expected %d\n",
+ (unsigned int)fw->size, size + 4);
+ ret = -EINVAL;
+ }
+
+ /* compute checksum */
+ p = (const __be32 *)fw->data;
+ for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
+ csum += ntohl(p[i]);
+
+ if (csum != 0xffffffff) {
+ CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+ csum);
+ ret = -EINVAL;
+ }
+
+ for (i = 0; i < size / 4 ; i++) {
+ *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
+ *cache++ = be32_to_cpu(p[i]) & 0xffff;
+ }
+
+ release_firmware(fw);
+
+ return ret;
+}
static int upgrade_fw(struct adapter *adap)
{
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 870d44992c7..e78d341cbd6 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -3682,6 +3682,8 @@ static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
{
mac->adapter = adapter;
+ if (!adapter->params.vpd.xauicfg[1])
+ index = 0;
mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
mac->nucast = 1;
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index f87f9435049..0109ee4f2f9 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -447,11 +447,12 @@ int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
- if (fc & PAUSE_TX)
- val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(
- t3_read_reg(adap,
- A_XGM_RX_MAX_PKT_SIZE
- + oft)) / 8);
+ if (fc & PAUSE_TX) {
+ u32 rx_max_pkt_size =
+ G_RXMAXPKTSIZE(t3_read_reg(adap,
+ A_XGM_RX_MAX_PKT_SIZE + oft));
+ val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
+ }
t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index e1af089064b..6b13f4fd2e9 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -226,7 +226,7 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_unlock_irqrestore(&de600_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 55d2bb67cff..45794f6cb0f 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -542,7 +542,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
spin_unlock_irqrestore(&de620_lock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*****************************************************
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index 2b22e580c4d..a31696a3928 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -902,7 +902,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -933,7 +933,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void lance_load_multicast(struct net_device *dev)
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 102b8d43971..b2e0a8fc21d 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3218,7 +3218,7 @@ static int dfx_xmt_queue_pkt(
bp->xmt_length_errors++; /* bump error counter */
netif_wake_queue(dev);
dev_kfree_skb(skb);
- return(0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
/*
* See if adapter link is available, if not, free buffer
@@ -3241,7 +3241,7 @@ static int dfx_xmt_queue_pkt(
bp->xmt_discards++; /* bump error counter */
dev_kfree_skb(skb); /* free sk_buff now */
netif_wake_queue(dev);
- return(0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
}
@@ -3345,7 +3345,7 @@ static int dfx_xmt_queue_pkt(
dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
spin_unlock_irqrestore(&bp->lock, flags);
netif_wake_queue(dev);
- return(0); /* packet queued to adapter */
+ return NETDEV_TX_OK; /* packet queued to adapter */
}
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 97ea2d6d3fe..adb997c5bb5 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -1793,7 +1793,7 @@ static int __init get_hw_addr(struct net_device *dev)
static int load_packet(struct net_device *dev, struct sk_buff *skb)
{
struct depca_private *lp = netdev_priv(dev);
- int i, entry, end, len, status = 0;
+ int i, entry, end, len, status = NETDEV_TX_OK;
entry = lp->tx_new; /* Ring around buffer number. */
end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index dd771dea6ae..a2bc4158259 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -92,6 +92,7 @@ typedef struct board_info {
u16 tx_pkt_cnt;
u16 queue_pkt_len;
u16 queue_start_addr;
+ u16 queue_ip_summed;
u16 dbug_cnt;
u8 io_mode; /* 0:word, 2:byte */
u8 phy_addr;
@@ -124,6 +125,10 @@ typedef struct board_info {
struct mii_if_info mii;
u32 msg_enable;
+
+ int rx_csum;
+ int can_csum;
+ int ip_summed;
} board_info_t;
/* debug code */
@@ -460,6 +465,40 @@ static int dm9000_nway_reset(struct net_device *dev)
return mii_nway_restart(&dm->mii);
}
+static uint32_t dm9000_get_rx_csum(struct net_device *dev)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ return dm->rx_csum;
+}
+
+static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ unsigned long flags;
+
+ if (dm->can_csum) {
+ dm->rx_csum = data;
+
+ spin_lock_irqsave(&dm->lock, flags);
+ iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0);
+ spin_unlock_irqrestore(&dm->lock, flags);
+
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+ int ret = -EOPNOTSUPP;
+
+ if (dm->can_csum)
+ ret = ethtool_op_set_tx_csum(dev, data);
+ return ret;
+}
+
static u32 dm9000_get_link(struct net_device *dev)
{
board_info_t *dm = to_dm9000_board(dev);
@@ -540,6 +579,10 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
.get_eeprom_len = dm9000_get_eeprom_len,
.get_eeprom = dm9000_get_eeprom,
.set_eeprom = dm9000_set_eeprom,
+ .get_rx_csum = dm9000_get_rx_csum,
+ .set_rx_csum = dm9000_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = dm9000_set_tx_csum,
};
static void dm9000_show_carrier(board_info_t *db,
@@ -685,6 +728,9 @@ dm9000_init_dm9000(struct net_device *dev)
/* I/O mode */
db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
+ /* Checksum mode */
+ dm9000_set_rx_csum(dev, db->rx_csum);
+
/* GPIO0 on pre-activate PHY */
iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
@@ -743,6 +789,29 @@ static void dm9000_timeout(struct net_device *dev)
spin_unlock_irqrestore(&db->lock, flags);
}
+static void dm9000_send_packet(struct net_device *dev,
+ int ip_summed,
+ u16 pkt_len)
+{
+ board_info_t *dm = to_dm9000_board(dev);
+
+ /* The DM9000 is not smart enough to leave fragmented packets alone. */
+ if (dm->ip_summed != ip_summed) {
+ if (ip_summed == CHECKSUM_NONE)
+ iow(dm, DM9000_TCCR, 0);
+ else
+ iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
+ dm->ip_summed = ip_summed;
+ }
+
+ /* Set TX length to DM9000 */
+ iow(dm, DM9000_TXPLL, pkt_len);
+ iow(dm, DM9000_TXPLH, pkt_len >> 8);
+
+ /* Issue TX polling command */
+ iow(dm, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
+}
+
/*
* Hardware start transmission.
* Send a packet to media from the upper layer.
@@ -769,17 +838,11 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
db->tx_pkt_cnt++;
/* TX control: First packet immediately send, second packet queue */
if (db->tx_pkt_cnt == 1) {
- /* Set TX length to DM9000 */
- iow(db, DM9000_TXPLL, skb->len);
- iow(db, DM9000_TXPLH, skb->len >> 8);
-
- /* Issue TX polling command */
- iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
-
- dev->trans_start = jiffies; /* save the time stamp */
+ dm9000_send_packet(dev, skb->ip_summed, skb->len);
} else {
/* Second packet */
db->queue_pkt_len = skb->len;
+ db->queue_ip_summed = skb->ip_summed;
netif_stop_queue(dev);
}
@@ -788,7 +851,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -809,12 +872,9 @@ static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status);
/* Queue packet check & send */
- if (db->tx_pkt_cnt > 0) {
- iow(db, DM9000_TXPLL, db->queue_pkt_len);
- iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8);
- iow(db, DM9000_TCR, TCR_TXREQ);
- dev->trans_start = jiffies;
- }
+ if (db->tx_pkt_cnt > 0)
+ dm9000_send_packet(dev, db->queue_ip_summed,
+ db->queue_pkt_len);
netif_wake_queue(dev);
}
}
@@ -846,14 +906,14 @@ dm9000_rx(struct net_device *dev)
rxbyte = readb(db->io_data);
/* Status check: this byte must be 0 or 1 */
- if (rxbyte > DM9000_PKT_RDY) {
+ if (rxbyte & DM9000_PKT_ERR) {
dev_warn(db->dev, "status check fail: %d\n", rxbyte);
iow(db, DM9000_RCR, 0x00); /* Stop Device */
iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */
return;
}
- if (rxbyte != DM9000_PKT_RDY)
+ if (!(rxbyte & DM9000_PKT_RDY))
return;
/* A packet ready now & Get status/length */
@@ -914,6 +974,12 @@ dm9000_rx(struct net_device *dev)
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev);
+ if (db->rx_csum) {
+ if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ }
netif_rx(skb);
dev->stats.rx_packets++;
@@ -922,7 +988,7 @@ dm9000_rx(struct net_device *dev)
(db->dumpblk)(db->io_data, RxLen);
}
- } while (rxbyte == DM9000_PKT_RDY);
+ } while (rxbyte & DM9000_PKT_RDY);
}
static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
@@ -1349,6 +1415,13 @@ dm9000_probe(struct platform_device *pdev)
db->type = TYPE_DM9000E;
}
+ /* dm9000a/b are capable of hardware checksum offload */
+ if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
+ db->can_csum = 1;
+ db->rx_csum = 1;
+ ndev->features |= NETIF_F_IP_CSUM;
+ }
+
/* from this point we assume that we have found a DM9000 */
/* driver system function */
@@ -1410,9 +1483,10 @@ out:
}
static int
-dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
+dm9000_drv_suspend(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
board_info_t *db;
if (ndev) {
@@ -1428,9 +1502,10 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state)
}
static int
-dm9000_drv_resume(struct platform_device *dev)
+dm9000_drv_resume(struct device *dev)
{
- struct net_device *ndev = platform_get_drvdata(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct net_device *ndev = platform_get_drvdata(pdev);
board_info_t *db = netdev_priv(ndev);
if (ndev) {
@@ -1447,6 +1522,11 @@ dm9000_drv_resume(struct platform_device *dev)
return 0;
}
+static struct dev_pm_ops dm9000_drv_pm_ops = {
+ .suspend = dm9000_drv_suspend,
+ .resume = dm9000_drv_resume,
+};
+
static int __devexit
dm9000_drv_remove(struct platform_device *pdev)
{
@@ -1466,11 +1546,10 @@ static struct platform_driver dm9000_driver = {
.driver = {
.name = "dm9000",
.owner = THIS_MODULE,
+ .pm = &dm9000_drv_pm_ops,
},
.probe = dm9000_probe,
.remove = __devexit_p(dm9000_drv_remove),
- .suspend = dm9000_drv_suspend,
- .resume = dm9000_drv_resume,
};
static int __init
diff --git a/drivers/net/dm9000.h b/drivers/net/dm9000.h
index ba25cf54142..80817c2edfb 100644
--- a/drivers/net/dm9000.h
+++ b/drivers/net/dm9000.h
@@ -45,6 +45,10 @@
#define DM9000_CHIPR 0x2C
#define DM9000_SMCR 0x2F
+#define DM9000_ETXCSR 0x30
+#define DM9000_TCCR 0x31
+#define DM9000_RCSR 0x32
+
#define CHIPR_DM9000A 0x19
#define CHIPR_DM9000B 0x1B
@@ -131,7 +135,21 @@
#define GPCR_GEP_CNTL (1<<0)
+#define TCCR_IP (1<<0)
+#define TCCR_TCP (1<<1)
+#define TCCR_UDP (1<<2)
+
+#define RCSR_UDP_BAD (1<<7)
+#define RCSR_TCP_BAD (1<<6)
+#define RCSR_IP_BAD (1<<5)
+#define RCSR_UDP (1<<4)
+#define RCSR_TCP (1<<3)
+#define RCSR_IP (1<<2)
+#define RCSR_CSUM (1<<1)
+#define RCSR_DISCARD (1<<0)
+
#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */
+#define DM9000_PKT_ERR 0x02
#define DM9000_PKT_MAX 1536 /* Received packet max size */
/* DM9000A / DM9000B definitions */
diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c
index 33fa9eee4ca..2818d5de394 100644
--- a/drivers/net/dnet.c
+++ b/drivers/net/dnet.c
@@ -596,7 +596,7 @@ static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void dnet_reset_hw(struct dnet *bp)
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 8ebd7d78940..713ce6c532c 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -85,7 +85,7 @@ static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 41b648a67fe..569df19f0df 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1720,7 +1720,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
netdev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int e100_tx_clean(struct nic *nic)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index e9a416f4016..1a4f89c66a2 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -111,6 +111,9 @@ do { \
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
+#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */
+
/* this is the size past which hardware will drop packets when setting LPE=0 */
#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
@@ -137,7 +140,7 @@ do { \
#define E1000_FC_HIGH_DIFF 0x1638 /* High: 5688 bytes below Rx FIFO size */
#define E1000_FC_LOW_DIFF 0x1640 /* Low: 5696 bytes below Rx FIFO size */
-#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */
+#define E1000_FC_PAUSE_TIME 0xFFFF /* pause for the max or until send xon */
/* How many Tx Descriptors do we need to call netif_wake_queue ? */
#define E1000_TX_QUEUE_WAKE 16
@@ -161,6 +164,7 @@ do { \
struct e1000_buffer {
struct sk_buff *skb;
dma_addr_t dma;
+ struct page *page;
unsigned long time_stamp;
u16 length;
u16 next_to_watch;
@@ -202,6 +206,7 @@ struct e1000_rx_ring {
unsigned int next_to_clean;
/* array of buffer information structs */
struct e1000_buffer *buffer_info;
+ struct sk_buff *rx_skb_top;
/* cpu for rx queue */
int cpu;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index c854c96f5ab..27f996a2010 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1904,6 +1904,53 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
return 0;
}
+static int e1000_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->hw.mac_type < e1000_82545)
+ return -EOPNOTSUPP;
+
+ if (adapter->itr_setting <= 3)
+ ec->rx_coalesce_usecs = adapter->itr_setting;
+ else
+ ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+ return 0;
+}
+
+static int e1000_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (hw->mac_type < e1000_82545)
+ return -EOPNOTSUPP;
+
+ if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
+ ((ec->rx_coalesce_usecs > 3) &&
+ (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
+ (ec->rx_coalesce_usecs == 2))
+ return -EINVAL;
+
+ if (ec->rx_coalesce_usecs <= 3) {
+ adapter->itr = 20000;
+ adapter->itr_setting = ec->rx_coalesce_usecs;
+ } else {
+ adapter->itr = (1000000 / ec->rx_coalesce_usecs);
+ adapter->itr_setting = adapter->itr & ~3;
+ }
+
+ if (adapter->itr_setting != 0)
+ ew32(ITR, 1000000000 / (adapter->itr * 256));
+ else
+ ew32(ITR, 0);
+
+ return 0;
+}
+
static int e1000_nway_reset(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1978,7 +2025,9 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_strings = e1000_get_strings,
.phys_id = e1000_phys_id,
.get_ethtool_stats = e1000_get_ethtool_stats,
- .get_sset_count = e1000_get_sset_count,
+ .get_sset_count = e1000_get_sset_count,
+ .get_coalesce = e1000_get_coalesce,
+ .set_coalesce = e1000_set_coalesce,
};
void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index e1a3fc1303e..1e5ae112d57 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -1955,7 +1955,7 @@ static s32 e1000_setup_copper_link(struct e1000_hw *hw)
s32 ret_val;
u16 i;
u16 phy_data;
- u16 reg_data;
+ u16 reg_data = 0;
DEBUGFUNC("e1000_setup_copper_link");
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 99fce2c5dd2..a8866bdbb67 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -523,11 +523,8 @@ s32 e1000_check_phy_reset_block(struct e1000_hw *hw);
/* The sizes (in bytes) of a ethernet packet */
#define ENET_HEADER_SIZE 14
-#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* With FCS */
#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* With FCS */
#define ETHERNET_FCS_SIZE 4
-#define MAXIMUM_ETHERNET_PACKET_SIZE \
- (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
#define MINIMUM_ETHERNET_PACKET_SIZE \
(MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
#define CRC_LENGTH ETHERNET_FCS_SIZE
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 5b8cbdb4b52..d7df00c2dbd 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -137,9 +137,15 @@ static int e1000_clean(struct napi_struct *napi, int budget);
static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do);
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do);
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
- struct e1000_rx_ring *rx_ring,
+ struct e1000_rx_ring *rx_ring,
int cleaned_count);
+static void e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int cleaned_count);
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
int cmd);
@@ -635,8 +641,8 @@ void e1000_reset(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 pba = 0, tx_space, min_tx_space, min_rx_space;
- u16 fc_high_water_mark = E1000_FC_HIGH_DIFF;
bool legacy_pba_adjust = false;
+ u16 hwm;
/* Repartition Pba for greater than 9k mtu
* To take effect CTRL.RST is required.
@@ -680,7 +686,7 @@ void e1000_reset(struct e1000_adapter *adapter)
}
if (legacy_pba_adjust) {
- if (adapter->netdev->mtu > E1000_RXBUFFER_8192)
+ if (hw->max_frame_size > E1000_RXBUFFER_8192)
pba -= 8; /* allocate more FIFO for Tx */
if (hw->mac_type == e1000_82547) {
@@ -690,14 +696,14 @@ void e1000_reset(struct e1000_adapter *adapter)
(E1000_PBA_40K - pba) << E1000_PBA_BYTES_SHIFT;
atomic_set(&adapter->tx_fifo_stall, 0);
}
- } else if (hw->max_frame_size > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ } else if (hw->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) {
/* adjust PBA for jumbo frames */
ew32(PBA, pba);
/* To maintain wire speed transmits, the Tx FIFO should be
- * large enough to accomodate two full transmit packets,
+ * large enough to accommodate two full transmit packets,
* rounded up to the next 1KB and expressed in KB. Likewise,
- * the Rx FIFO should be large enough to accomodate at least
+ * the Rx FIFO should be large enough to accommodate at least
* one full receive packet and is similarly rounded up and
* expressed in KB. */
pba = er32(PBA);
@@ -705,13 +711,17 @@ void e1000_reset(struct e1000_adapter *adapter)
tx_space = pba >> 16;
/* lower 16 bits has Rx packet buffer allocation size in KB */
pba &= 0xffff;
- /* don't include ethernet FCS because hardware appends/strips */
- min_rx_space = adapter->netdev->mtu + ENET_HEADER_SIZE +
- VLAN_TAG_SIZE;
- min_tx_space = min_rx_space;
- min_tx_space *= 2;
+ /*
+ * the tx fifo also stores 16 bytes of information about the tx
+ * but don't include ethernet FCS because hardware appends it
+ */
+ min_tx_space = (hw->max_frame_size +
+ sizeof(struct e1000_tx_desc) -
+ ETH_FCS_LEN) * 2;
min_tx_space = ALIGN(min_tx_space, 1024);
min_tx_space >>= 10;
+ /* software strips receive CRC, so leave room for it */
+ min_rx_space = hw->max_frame_size;
min_rx_space = ALIGN(min_rx_space, 1024);
min_rx_space >>= 10;
@@ -748,23 +758,22 @@ void e1000_reset(struct e1000_adapter *adapter)
ew32(PBA, pba);
- /* flow control settings */
- /* Set the FC high water mark to 90% of the FIFO size.
- * Required to clear last 3 LSB */
- fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8;
- /* We can't use 90% on small FIFOs because the remainder
- * would be less than 1 full frame. In this case, we size
- * it to allow at least a full frame above the high water
- * mark. */
- if (pba < E1000_PBA_16K)
- fc_high_water_mark = (pba * 1024) - 1600;
-
- hw->fc_high_water = fc_high_water_mark;
- hw->fc_low_water = fc_high_water_mark - 8;
- if (hw->mac_type == e1000_80003es2lan)
- hw->fc_pause_time = 0xFFFF;
- else
- hw->fc_pause_time = E1000_FC_PAUSE_TIME;
+ /*
+ * flow control settings:
+ * The high water mark must be low enough to fit one full frame
+ * (or the size used for early receive) above it in the Rx FIFO.
+ * Set it to the lower of:
+ * - 90% of the Rx FIFO size, and
+ * - the full Rx FIFO size minus the early receive size (for parts
+ * with ERT support assuming ERT set to E1000_ERT_2048), or
+ * - the full Rx FIFO size minus one full frame
+ */
+ hwm = min(((pba << 10) * 9 / 10),
+ ((pba << 10) - hw->max_frame_size));
+
+ hw->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */
+ hw->fc_low_water = hw->fc_high_water - 8;
+ hw->fc_pause_time = E1000_FC_PAUSE_TIME;
hw->fc_send_xon = 1;
hw->fc = hw->original_fc;
@@ -1862,6 +1871,7 @@ setup_rx_desc_die:
rxdr->next_to_clean = 0;
rxdr->next_to_use = 0;
+ rxdr->rx_skb_top = NULL;
return 0;
}
@@ -1968,10 +1978,17 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 rdlen, rctl, rxcsum, ctrl_ext;
- rdlen = adapter->rx_ring[0].count *
- sizeof(struct e1000_rx_desc);
- adapter->clean_rx = e1000_clean_rx_irq;
- adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+ if (adapter->netdev->mtu > ETH_DATA_LEN) {
+ rdlen = adapter->rx_ring[0].count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_jumbo_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_jumbo_rx_buffers;
+ } else {
+ rdlen = adapter->rx_ring[0].count *
+ sizeof(struct e1000_rx_desc);
+ adapter->clean_rx = e1000_clean_rx_irq;
+ adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+ }
/* disable receives while setting up the descriptors */
rctl = er32(RCTL);
@@ -2185,26 +2202,39 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
/* Free all the Rx ring sk_buffs */
for (i = 0; i < rx_ring->count; i++) {
buffer_info = &rx_ring->buffer_info[i];
- if (buffer_info->dma) {
- pci_unmap_single(pdev,
- buffer_info->dma,
- buffer_info->length,
- PCI_DMA_FROMDEVICE);
+ if (buffer_info->dma &&
+ adapter->clean_rx == e1000_clean_rx_irq) {
+ pci_unmap_single(pdev, buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ } else if (buffer_info->dma &&
+ adapter->clean_rx == e1000_clean_jumbo_rx_irq) {
+ pci_unmap_page(pdev, buffer_info->dma,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
}
buffer_info->dma = 0;
-
+ if (buffer_info->page) {
+ put_page(buffer_info->page);
+ buffer_info->page = NULL;
+ }
if (buffer_info->skb) {
dev_kfree_skb(buffer_info->skb);
buffer_info->skb = NULL;
}
}
+ /* there also may be some cached data from a chained receive */
+ if (rx_ring->rx_skb_top) {
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ }
+
size = sizeof(struct e1000_buffer) * rx_ring->count;
memset(rx_ring->buffer_info, 0, size);
/* Zero out the descriptor ring */
-
memset(rx_ring->desc, 0, rx_ring->size);
rx_ring->next_to_clean = 0;
@@ -3450,7 +3480,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
switch (hw->mac_type) {
case e1000_undefined ... e1000_82542_rev2_1:
case e1000_ich8lan:
- if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
return -EINVAL;
}
@@ -3463,7 +3493,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
&eeprom_data);
if ((hw->device_id != E1000_DEV_ID_82573L) ||
(eeprom_data & EEPROM_WORD1A_ASPM_MASK)) {
- if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
+ if (max_frame > (ETH_FRAME_LEN + ETH_FCS_LEN)) {
DPRINTK(PROBE, ERR,
"Jumbo Frames not supported.\n");
return -EINVAL;
@@ -3489,8 +3519,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
/* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
* means we reserve 2 more, this pushes us to allocate from the next
- * larger slab size
- * i.e. RXBUFFER_2048 --> size-4096 slab */
+ * larger slab size.
+ * i.e. RXBUFFER_2048 --> size-4096 slab
+ * however with the new *_jumbo_rx* routines, jumbo receives will use
+ * fragmented skbs */
if (max_frame <= E1000_RXBUFFER_256)
adapter->rx_buffer_len = E1000_RXBUFFER_256;
@@ -3500,16 +3532,16 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
adapter->rx_buffer_len = E1000_RXBUFFER_1024;
else if (max_frame <= E1000_RXBUFFER_2048)
adapter->rx_buffer_len = E1000_RXBUFFER_2048;
- else if (max_frame <= E1000_RXBUFFER_4096)
- adapter->rx_buffer_len = E1000_RXBUFFER_4096;
- else if (max_frame <= E1000_RXBUFFER_8192)
- adapter->rx_buffer_len = E1000_RXBUFFER_8192;
- else if (max_frame <= E1000_RXBUFFER_16384)
+ else
+#if (PAGE_SIZE >= E1000_RXBUFFER_16384)
adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+#elif (PAGE_SIZE >= E1000_RXBUFFER_4096)
+ adapter->rx_buffer_len = PAGE_SIZE;
+#endif
/* adjust allocation if LPE protects us, and we aren't using SBP */
if (!hw->tbi_compatibility_on &&
- ((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) ||
+ ((max_frame == (ETH_FRAME_LEN + ETH_FCS_LEN)) ||
(max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)))
adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
@@ -3987,9 +4019,227 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
}
/**
+ * e1000_consume_page - helper function
+ **/
+static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
+ u16 length)
+{
+ bi->page = NULL;
+ skb->len += length;
+ skb->data_len += length;
+ skb->truesize += length;
+}
+
+/**
+ * e1000_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ */
+static void e1000_receive_skb(struct e1000_adapter *adapter, u8 status,
+ __le16 vlan, struct sk_buff *skb)
+{
+ if (unlikely(adapter->vlgrp && (status & E1000_RXD_STAT_VP))) {
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+ le16_to_cpu(vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
+ } else {
+ netif_receive_skb(skb);
+ }
+}
+
+/**
+ * e1000_clean_jumbo_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ * @rx_ring: ring to clean
+ * @work_done: amount of napi work completed this call
+ * @work_to_do: max amount of work allowed for this call to do
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ */
+static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring,
+ int *work_done, int work_to_do)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_rx_desc *rx_desc, *next_rxd;
+ struct e1000_buffer *buffer_info, *next_buffer;
+ unsigned long irq_flags;
+ u32 length;
+ unsigned int i;
+ int cleaned_count = 0;
+ bool cleaned = false;
+ unsigned int total_rx_bytes=0, total_rx_packets=0;
+
+ i = rx_ring->next_to_clean;
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (rx_desc->status & E1000_RXD_STAT_DD) {
+ struct sk_buff *skb;
+ u8 status;
+
+ if (*work_done >= work_to_do)
+ break;
+ (*work_done)++;
+
+ status = rx_desc->status;
+ skb = buffer_info->skb;
+ buffer_info->skb = NULL;
+
+ if (++i == rx_ring->count) i = 0;
+ next_rxd = E1000_RX_DESC(*rx_ring, i);
+ prefetch(next_rxd);
+
+ next_buffer = &rx_ring->buffer_info[i];
+
+ cleaned = true;
+ cleaned_count++;
+ pci_unmap_page(pdev, buffer_info->dma, buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
+
+ length = le16_to_cpu(rx_desc->length);
+
+ /* errors is only valid for DD + EOP descriptors */
+ if (unlikely((status & E1000_RXD_STAT_EOP) &&
+ (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK))) {
+ u8 last_byte = *(skb->data + length - 1);
+ if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
+ last_byte)) {
+ spin_lock_irqsave(&adapter->stats_lock,
+ irq_flags);
+ e1000_tbi_adjust_stats(hw, &adapter->stats,
+ length, skb->data);
+ spin_unlock_irqrestore(&adapter->stats_lock,
+ irq_flags);
+ length--;
+ } else {
+ /* recycle both page and skb */
+ buffer_info->skb = skb;
+ /* an error means any chain goes out the window
+ * too */
+ if (rx_ring->rx_skb_top)
+ dev_kfree_skb(rx_ring->rx_skb_top);
+ rx_ring->rx_skb_top = NULL;
+ goto next_desc;
+ }
+ }
+
+#define rxtop rx_ring->rx_skb_top
+ if (!(status & E1000_RXD_STAT_EOP)) {
+ /* this descriptor is only the beginning (or middle) */
+ if (!rxtop) {
+ /* this is the beginning of a chain */
+ rxtop = skb;
+ skb_fill_page_desc(rxtop, 0, buffer_info->page,
+ 0, length);
+ } else {
+ /* this is the middle of a chain */
+ skb_fill_page_desc(rxtop,
+ skb_shinfo(rxtop)->nr_frags,
+ buffer_info->page, 0, length);
+ /* re-use the skb, only consumed the page */
+ buffer_info->skb = skb;
+ }
+ e1000_consume_page(buffer_info, rxtop, length);
+ goto next_desc;
+ } else {
+ if (rxtop) {
+ /* end of the chain */
+ skb_fill_page_desc(rxtop,
+ skb_shinfo(rxtop)->nr_frags,
+ buffer_info->page, 0, length);
+ /* re-use the current skb, we only consumed the
+ * page */
+ buffer_info->skb = skb;
+ skb = rxtop;
+ rxtop = NULL;
+ e1000_consume_page(buffer_info, skb, length);
+ } else {
+ /* no chain, got EOP, this buf is the packet
+ * copybreak to save the put_page/alloc_page */
+ if (length <= copybreak &&
+ skb_tailroom(skb) >= length) {
+ u8 *vaddr;
+ vaddr = kmap_atomic(buffer_info->page,
+ KM_SKB_DATA_SOFTIRQ);
+ memcpy(skb_tail_pointer(skb), vaddr, length);
+ kunmap_atomic(vaddr,
+ KM_SKB_DATA_SOFTIRQ);
+ /* re-use the page, so don't erase
+ * buffer_info->page */
+ skb_put(skb, length);
+ } else {
+ skb_fill_page_desc(skb, 0,
+ buffer_info->page, 0,
+ length);
+ e1000_consume_page(buffer_info, skb,
+ length);
+ }
+ }
+ }
+
+ /* Receive Checksum Offload XXX recompute due to CRC strip? */
+ e1000_rx_checksum(adapter,
+ (u32)(status) |
+ ((u32)(rx_desc->errors) << 24),
+ le16_to_cpu(rx_desc->csum), skb);
+
+ pskb_trim(skb, skb->len - 4);
+
+ /* probably a little skewed due to removing CRC */
+ total_rx_bytes += skb->len;
+ total_rx_packets++;
+
+ /* eth type trans needs skb->data to point to something */
+ if (!pskb_may_pull(skb, ETH_HLEN)) {
+ DPRINTK(DRV, ERR, "pskb_may_pull failed.\n");
+ dev_kfree_skb(skb);
+ goto next_desc;
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ e1000_receive_skb(adapter, status, rx_desc->special, skb);
+
+next_desc:
+ rx_desc->status = 0;
+
+ /* return some buffers to hardware, one at a time is too slow */
+ if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
+ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
+ cleaned_count = 0;
+ }
+
+ /* use prefetched values */
+ rx_desc = next_rxd;
+ buffer_info = next_buffer;
+ }
+ rx_ring->next_to_clean = i;
+
+ cleaned_count = E1000_DESC_UNUSED(rx_ring);
+ if (cleaned_count)
+ adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
+
+ adapter->total_rx_packets += total_rx_packets;
+ adapter->total_rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_bytes += total_rx_bytes;
+ adapter->net_stats.rx_packets += total_rx_packets;
+ return cleaned;
+}
+
+/**
* e1000_clean_rx_irq - Send received data up the network stack; legacy
* @adapter: board private structure
- **/
+ * @rx_ring: ring to clean
+ * @work_done: amount of napi work completed this call
+ * @work_to_do: max amount of work allowed for this call to do
+ */
static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_rx_ring *rx_ring,
int *work_done, int work_to_do)
@@ -4001,7 +4251,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
struct e1000_buffer *buffer_info, *next_buffer;
unsigned long flags;
u32 length;
- u8 last_byte;
unsigned int i;
int cleaned_count = 0;
bool cleaned = false;
@@ -4033,9 +4282,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
cleaned = true;
cleaned_count++;
- pci_unmap_single(pdev,
- buffer_info->dma,
- buffer_info->length,
+ pci_unmap_single(pdev, buffer_info->dma, buffer_info->length,
PCI_DMA_FROMDEVICE);
buffer_info->dma = 0;
@@ -4052,7 +4299,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
}
if (unlikely(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) {
- last_byte = *(skb->data + length - 1);
+ u8 last_byte = *(skb->data + length - 1);
if (TBI_ACCEPT(hw, status, rx_desc->errors, length,
last_byte)) {
spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -4107,13 +4354,7 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev);
- if (unlikely(adapter->vlgrp &&
- (status & E1000_RXD_STAT_VP))) {
- vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
- le16_to_cpu(rx_desc->special));
- } else {
- netif_receive_skb(skb);
- }
+ e1000_receive_skb(adapter, status, rx_desc->special, skb);
next_desc:
rx_desc->status = 0;
@@ -4142,6 +4383,114 @@ next_desc:
}
/**
+ * e1000_alloc_jumbo_rx_buffers - Replace used jumbo receive buffers
+ * @adapter: address of board private structure
+ * @rx_ring: pointer to receive ring structure
+ * @cleaned_count: number of buffers to allocate this pass
+ **/
+
+static void
+e1000_alloc_jumbo_rx_buffers(struct e1000_adapter *adapter,
+ struct e1000_rx_ring *rx_ring, int cleaned_count)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct e1000_rx_desc *rx_desc;
+ struct e1000_buffer *buffer_info;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned int bufsz = 256 -
+ 16 /*for skb_reserve */ -
+ NET_IP_ALIGN;
+
+ i = rx_ring->next_to_use;
+ buffer_info = &rx_ring->buffer_info[i];
+
+ while (cleaned_count--) {
+ skb = buffer_info->skb;
+ if (skb) {
+ skb_trim(skb, 0);
+ goto check_page;
+ }
+
+ skb = netdev_alloc_skb(netdev, bufsz);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+
+ /* Fix for errata 23, can't cross 64kB boundary */
+ if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+ struct sk_buff *oldskb = skb;
+ DPRINTK(PROBE, ERR, "skb align check failed: %u bytes "
+ "at %p\n", bufsz, skb->data);
+ /* Try again, without freeing the previous */
+ skb = netdev_alloc_skb(netdev, bufsz);
+ /* Failed allocation, critical failure */
+ if (!skb) {
+ dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+
+ if (!e1000_check_64k_bound(adapter, skb->data, bufsz)) {
+ /* give up */
+ dev_kfree_skb(skb);
+ dev_kfree_skb(oldskb);
+ break; /* while (cleaned_count--) */
+ }
+
+ /* Use new allocation */
+ dev_kfree_skb(oldskb);
+ }
+ /* Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ buffer_info->skb = skb;
+ buffer_info->length = adapter->rx_buffer_len;
+check_page:
+ /* allocate a new page if necessary */
+ if (!buffer_info->page) {
+ buffer_info->page = alloc_page(GFP_ATOMIC);
+ if (unlikely(!buffer_info->page)) {
+ adapter->alloc_rx_buff_failed++;
+ break;
+ }
+ }
+
+ if (!buffer_info->dma)
+ buffer_info->dma = pci_map_page(pdev,
+ buffer_info->page, 0,
+ buffer_info->length,
+ PCI_DMA_FROMDEVICE);
+
+ rx_desc = E1000_RX_DESC(*rx_ring, i);
+ rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+ if (unlikely(++i == rx_ring->count))
+ i = 0;
+ buffer_info = &rx_ring->buffer_info[i];
+ }
+
+ if (likely(rx_ring->next_to_use != i)) {
+ rx_ring->next_to_use = i;
+ if (unlikely(i-- == 0))
+ i = (rx_ring->count - 1);
+
+ /* Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64). */
+ wmb();
+ writel(i, adapter->hw.hw_addr + rx_ring->rdt);
+ }
+}
+
+/**
* e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
* @adapter: address of board private structure
**/
@@ -4186,6 +4535,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
/* Failed allocation, critical failure */
if (!skb) {
dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
break;
}
@@ -4193,6 +4543,7 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
/* give up */
dev_kfree_skb(skb);
dev_kfree_skb(oldskb);
+ adapter->alloc_rx_buff_failed++;
break; /* while !buffer_info->skb */
}
@@ -4210,9 +4561,14 @@ static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
map_skb:
buffer_info->dma = pci_map_single(pdev,
skb->data,
- adapter->rx_buffer_len,
+ buffer_info->length,
PCI_DMA_FROMDEVICE);
+ /*
+ * XXX if it was allocated cleanly it will never map to a
+ * boundary crossing
+ */
+
/* Fix for errata 23, can't cross 64kB boundary */
if (!e1000_check_64k_bound(adapter,
(void *)(unsigned long)buffer_info->dma,
@@ -4229,6 +4585,7 @@ map_skb:
PCI_DMA_FROMDEVICE);
buffer_info->dma = 0;
+ adapter->alloc_rx_buff_failed++;
break; /* while !buffer_info->skb */
}
rx_desc = E1000_RX_DESC(*rx_ring, i);
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 4f700348534..53317a83857 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1145,7 +1145,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
netif_stop_queue (dev);
@@ -1178,7 +1178,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
eepro_en_int(ioaddr);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 1f016d66684..d1b6368faac 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -664,7 +664,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
if (buf->len < ETH_ZLEN) {
if (skb_padto(buf, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -691,7 +691,7 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
spin_unlock_irqrestore(&lp->lock, flags);
#endif
enable_irq(dev->irq);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index fc6cc038c7b..372d6c6a4e7 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -1299,7 +1299,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev)
priv->tx_skb = skb;
schedule_work(&priv->tx_work);
- return 0;
+ return NETDEV_TX_OK;
}
static void enc28j60_tx_work_handler(struct work_struct *work)
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index b60e27dfcfa..d6a7aa3142f 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -970,7 +970,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
/* Caution: the write order is important here, set the field with the
"ownership" bit last. */
@@ -1014,7 +1014,7 @@ static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, (int)skb->len, entry, ctrl_word,
(int)inl(dev->base_addr + TxSTAT));
- return 0;
+ return NETDEV_TX_OK;
}
static void epic_tx_error(struct net_device *dev, struct epic_private *ep,
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index 19b7dd98394..c0e69c5cae8 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -348,7 +348,7 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&eql->queue.lock);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 0d8b6da046f..97d5205edc8 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1064,7 +1064,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
buf = skb->data;
@@ -1126,7 +1126,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
status = 0;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void eth16i_rx(struct net_device *dev)
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index ceb6a9c357a..4dbe5f17327 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -894,7 +894,7 @@ static int ethoc_probe(struct platform_device *pdev)
mmio = devm_request_mem_region(&pdev->dev, res->start,
res->end - res->start + 1, res->name);
- if (!res) {
+ if (!mmio) {
dev_err(&pdev->dev, "cannot request I/O memory space\n");
ret = -ENXIO;
goto free;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 1e972328140..9c51bc813ad 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -868,7 +868,7 @@ static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
if (inb (EWRK3_FMQC) == 0)
netif_stop_queue (dev);
- return 0;
+ return NETDEV_TX_OK;
err_out:
ENABLE_IRQs;
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index ee51557e942..b2d617206bd 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -1375,7 +1375,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&np->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index d4b98074b1b..e3d99fe53ce 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -366,7 +366,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&fep->hw_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 75a09994d66..a2d69c1cd07 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -36,6 +36,7 @@
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#include <asm/mpc5xxx.h>
#include "fs_enet.h"
#include "fec.h"
@@ -103,11 +104,11 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- struct device_node *np = NULL;
struct resource res;
struct mii_bus *new_bus;
struct fec_info *fec;
- int ret = -ENOMEM, i;
+ int (*get_bus_freq)(struct device_node *) = match->data;
+ int ret = -ENOMEM, clock, speed;
new_bus = mdiobus_alloc();
if (!new_bus)
@@ -133,13 +134,35 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
if (!fec->fecp)
goto out_fec;
- fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+ if (get_bus_freq) {
+ clock = get_bus_freq(ofdev->node);
+ if (!clock) {
+ /* Use maximum divider if clock is unknown */
+ dev_warn(&ofdev->dev, "could not determine IPS clock\n");
+ clock = 0x3F * 5000000;
+ }
+ } else
+ clock = ppc_proc_freq;
+
+ /*
+ * Scale for a MII clock <= 2.5 MHz
+ * Note that only 6 bits (25:30) are available for MII speed.
+ */
+ speed = (clock + 4999999) / 5000000;
+ if (speed > 0x3F) {
+ speed = 0x3F;
+ dev_err(&ofdev->dev,
+ "MII clock (%d Hz) exceeds max (2.5 MHz)\n",
+ clock / speed);
+ }
+
+ fec->mii_speed = speed << 1;
setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
FEC_ECNTRL_ETHER_EN);
out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
- out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+ clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed);
new_bus->phy_mask = ~0;
new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
@@ -188,6 +211,12 @@ static struct of_device_id fs_enet_mdio_fec_match[] = {
{
.compatible = "fsl,pq1-fec-mdio",
},
+#if defined(CONFIG_PPC_MPC512x)
+ {
+ .compatible = "fsl,mpc5121-fec-mdio",
+ .data = mpc5xxx_get_bus_frequency,
+ },
+#endif
{},
};
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index f8ffcbf0bc3..056ba462578 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -297,7 +297,6 @@ static int gfar_probe(struct of_device *ofdev,
u32 tempval;
struct net_device *dev = NULL;
struct gfar_private *priv = NULL;
- DECLARE_MAC_BUF(mac);
int err = 0;
int len_devname;
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 9d5b62cb30f..4e8d3728e82 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1369,7 +1369,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n",
dev->name, hmp->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 981ab530e9a..6cb2bdfd7b1 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -255,7 +255,7 @@ static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int sp_open_dev(struct net_device *dev)
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 5e4b7afd068..e229edf3261 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -774,18 +774,18 @@ static int baycom_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] != 0) {
do_kiss_params(bc, skb->data, skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (bc->skb)
return NETDEV_TX_LOCKED;
/* strip KISS byte */
if (skb->len >= HDLCDRV_MAXFLEN+1 || skb->len < 3) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
bc->skb = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index abcd19a8bff..4c5f4dfbe05 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -305,7 +305,7 @@ static int bpq_xmit(struct sk_buff *skb, struct net_device *dev)
dev_queue_xmit(skb);
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 7459b3ac77a..950f3bb21f9 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -959,7 +959,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->ring_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index d034f8ca63c..16b060b9211 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -406,13 +406,13 @@ static int hdlcdrv_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->data[0] != 0) {
do_kiss_params(sm, skb->data, skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (sm->skb)
return NETDEV_TX_LOCKED;
netif_stop_queue(dev);
sm->skb = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index fda2fc83e9a..ac191ef2119 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -560,7 +560,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(skb);
}
- return 0;
+ return NETDEV_TX_OK;
}
static int ax_open_dev(struct net_device *dev)
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index d712e7af780..c5406525c1a 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1643,7 +1643,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
if (skb->len > scc->stat.bufsize || skb->len < 2) {
scc->dev_stat.tx_dropped++; /* bogus frame */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
scc->dev_stat.tx_packets++;
@@ -1656,7 +1656,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
if (kisscmd) {
scc_set_param(scc, kisscmd, *skb->data);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&scc->lock, flags);
@@ -1684,7 +1684,7 @@ static int scc_net_tx(struct sk_buff *skb, struct net_device *dev)
__scc_start_tx_timer(scc, t_dwait, 0);
}
spin_unlock_irqrestore(&scc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* ----> ioctl functions <---- */
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index b06691937ce..b85aa162314 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -600,7 +600,7 @@ static int yam_send_packet(struct sk_buff *skb, struct net_device *dev)
skb_queue_tail(&yp->send_queue, skb);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void yam_start_tx(struct net_device *dev, struct yam_port *yp)
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 1d3429a415e..d1b63387e9b 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1499,7 +1499,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
goto drop;
if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
/* Get Tx ring tail pointer */
if (lp->txrtail->next == lp->txrhead) {
@@ -1585,7 +1585,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
lp->stats.tx_bytes += skb->len;
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
drop:
dev_kfree_skb(skb);
@@ -1752,7 +1752,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk("hp100: %s: start_xmit: end\n", dev->name);
#endif
- return 0;
+ return NETDEV_TX_OK;
drop:
dev_kfree_skb(skb);
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index beb84213b67..5443558c439 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -1342,7 +1342,7 @@ static inline int emac_xmit_finish(struct emac_instance *dev, int len)
++dev->stats.tx_packets;
dev->stats.tx_bytes += len;
- return 0;
+ return NETDEV_TX_OK;
}
/* Tx lock BH */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 0995c438f28..76b295a1818 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -971,7 +971,7 @@ out: spin_lock_irqsave(&adapter->stats_lock, flags);
spin_unlock_irqrestore(&adapter->stats_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int ibmveth_poll(struct napi_struct *napi, int budget)
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 96713ef0629..0a79b451780 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -164,7 +164,7 @@ static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ifb_private *dp = netdev_priv(dev);
struct net_device_stats *stats = &dev->stats;
- int ret = 0;
+ int ret = NETDEV_TX_OK;
u32 from = G_TC_FROM(skb->tc_verd);
stats->rx_packets++;
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index ac28dd5a4fd..6158c0f3b20 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -53,7 +53,7 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *);
static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16);
static void igb_clear_hw_cntrs_82575(struct e1000_hw *);
static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *, u16);
-static s32 igb_configure_pcs_link_82575(struct e1000_hw *);
+static void igb_configure_pcs_link_82575(struct e1000_hw *);
static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *,
u16 *);
static s32 igb_get_phy_id_82575(struct e1000_hw *);
@@ -61,6 +61,7 @@ static void igb_release_swfw_sync_82575(struct e1000_hw *, u16);
static bool igb_sgmii_active_82575(struct e1000_hw *);
static s32 igb_reset_init_script_82575(struct e1000_hw *);
static s32 igb_read_mac_addr_82575(struct e1000_hw *);
+static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw);
static s32 igb_get_invariants_82575(struct e1000_hw *hw)
{
@@ -84,6 +85,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
case E1000_DEV_ID_82576_FIBER:
case E1000_DEV_ID_82576_SERDES:
case E1000_DEV_ID_82576_QUAD_COPPER:
+ case E1000_DEV_ID_82576_SERDES_QUAD:
mac->type = e1000_82576;
break;
default:
@@ -170,6 +172,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
size = 14;
nvm->word_size = 1 << size;
+ /* if 82576 then initialize mailbox parameters */
+ if (mac->type == e1000_82576)
+ igb_init_mbx_params_pf(hw);
+
/* setup PHY parameters */
if (phy->media_type != e1000_media_type_copper) {
phy->type = e1000_phy_none;
@@ -219,10 +225,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
return -E1000_ERR_PHY;
}
- /* if 82576 then initialize mailbox parameters */
- if (mac->type == e1000_82576)
- igb_init_mbx_params_pf(hw);
-
return 0;
}
@@ -764,98 +766,6 @@ static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed,
}
/**
- * igb_init_rx_addrs_82575 - Initialize receive address's
- * @hw: pointer to the HW structure
- * @rar_count: receive address registers
- *
- * Setups the receive address registers by setting the base receive address
- * register to the devices MAC address and clearing all the other receive
- * address registers to 0.
- **/
-static void igb_init_rx_addrs_82575(struct e1000_hw *hw, u16 rar_count)
-{
- u32 i;
- u8 addr[6] = {0,0,0,0,0,0};
- /*
- * This function is essentially the same as that of
- * e1000_init_rx_addrs_generic. However it also takes care
- * of the special case where the register offset of the
- * second set of RARs begins elsewhere. This is implicitly taken care by
- * function e1000_rar_set_generic.
- */
-
- hw_dbg("e1000_init_rx_addrs_82575");
-
- /* Setup the receive address */
- hw_dbg("Programming MAC Address into RAR[0]\n");
- hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
-
- /* Zero out the other (rar_entry_count - 1) receive addresses */
- hw_dbg("Clearing RAR[1-%u]\n", rar_count-1);
- for (i = 1; i < rar_count; i++)
- hw->mac.ops.rar_set(hw, addr, i);
-}
-
-/**
- * igb_update_mc_addr_list - Update Multicast addresses
- * @hw: pointer to the HW structure
- * @mc_addr_list: array of multicast addresses to program
- * @mc_addr_count: number of multicast addresses to program
- * @rar_used_count: the first RAR register free to program
- * @rar_count: total number of supported Receive Address Registers
- *
- * Updates the Receive Address Registers and Multicast Table Array.
- * The caller must have a packed mc_addr_list of multicast addresses.
- * The parameter rar_count will usually be hw->mac.rar_entry_count
- * unless there are workarounds that change this.
- **/
-void igb_update_mc_addr_list(struct e1000_hw *hw,
- u8 *mc_addr_list, u32 mc_addr_count,
- u32 rar_used_count, u32 rar_count)
-{
- u32 hash_value;
- u32 i;
- u8 addr[6] = {0,0,0,0,0,0};
- /*
- * This function is essentially the same as that of
- * igb_update_mc_addr_list_generic. However it also takes care
- * of the special case where the register offset of the
- * second set of RARs begins elsewhere. This is implicitly taken care by
- * function e1000_rar_set_generic.
- */
-
- /*
- * Load the first set of multicast addresses into the exact
- * filters (RAR). If there are not enough to fill the RAR
- * array, clear the filters.
- */
- for (i = rar_used_count; i < rar_count; i++) {
- if (mc_addr_count) {
- igb_rar_set(hw, mc_addr_list, i);
- mc_addr_count--;
- mc_addr_list += ETH_ALEN;
- } else {
- igb_rar_set(hw, addr, i);
- }
- }
-
- /* Clear the old settings from the MTA */
- hw_dbg("Clearing MTA\n");
- for (i = 0; i < hw->mac.mta_reg_count; i++) {
- array_wr32(E1000_MTA, i, 0);
- wrfl();
- }
-
- /* Load any remaining multicast addresses into the hash table. */
- for (; mc_addr_count > 0; mc_addr_count--) {
- hash_value = igb_hash_mc_addr(hw, mc_addr_list);
- hw_dbg("Hash value = 0x%03X\n", hash_value);
- igb_mta_set(hw, hash_value);
- mc_addr_list += ETH_ALEN;
- }
-}
-
-/**
* igb_shutdown_fiber_serdes_link_82575 - Remove link during power down
* @hw: pointer to the HW structure
*
@@ -866,9 +776,7 @@ void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw)
{
u32 reg;
- if (hw->mac.type != e1000_82576 ||
- (hw->phy.media_type != e1000_media_type_fiber &&
- hw->phy.media_type != e1000_media_type_internal_serdes))
+ if (hw->phy.media_type != e1000_media_type_internal_serdes)
return;
/* if the management interface is not enabled, then power down */
@@ -911,6 +819,12 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
if (ret_val)
hw_dbg("PCI-E Master disable polling has failed.\n");
+ /* set the completion timeout for interface */
+ ret_val = igb_set_pcie_completion_timeout(hw);
+ if (ret_val) {
+ hw_dbg("PCI-E Set completion timeout has failed.\n");
+ }
+
hw_dbg("Masking off all interrupts\n");
wr32(E1000_IMC, 0xffffffff);
@@ -943,7 +857,8 @@ static s32 igb_reset_hw_82575(struct e1000_hw *hw)
wr32(E1000_IMC, 0xffffffff);
icr = rd32(E1000_ICR);
- igb_check_alt_mac_addr(hw);
+ /* Install any alternate MAC address into RAR0 */
+ ret_val = igb_check_alt_mac_addr(hw);
return ret_val;
}
@@ -972,7 +887,8 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
igb_clear_vfta(hw);
/* Setup the receive address */
- igb_init_rx_addrs_82575(hw, rar_count);
+ igb_init_rx_addrs(hw, rar_count);
+
/* Zero out the Multicast HASH table */
hw_dbg("Zeroing the MTA\n");
for (i = 0; i < mac->mta_reg_count; i++)
@@ -1002,7 +918,7 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
**/
static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
{
- u32 ctrl, led_ctrl;
+ u32 ctrl;
s32 ret_val;
bool link;
@@ -1017,11 +933,6 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
break;
case e1000_phy_igp_3:
ret_val = igb_copper_link_setup_igp(hw);
- /* Setup activity LED */
- led_ctrl = rd32(E1000_LEDCTL);
- led_ctrl &= IGP_ACTIVITY_LED_MASK;
- led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
- wr32(E1000_LEDCTL, led_ctrl);
break;
default:
ret_val = -E1000_ERR_PHY;
@@ -1052,9 +963,7 @@ static s32 igb_setup_copper_link_82575(struct e1000_hw *hw)
}
}
- ret_val = igb_configure_pcs_link_82575(hw);
- if (ret_val)
- goto out;
+ igb_configure_pcs_link_82575(hw);
/*
* Check link status. Wait up to 100 microseconds for link to become
@@ -1163,14 +1072,14 @@ static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw)
* independent interface (sgmii) is being used. Configures the link
* for auto-negotiation or forces speed/duplex.
**/
-static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw)
+static void igb_configure_pcs_link_82575(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
u32 reg = 0;
if (hw->phy.media_type != e1000_media_type_copper ||
!(igb_sgmii_active_82575(hw)))
- goto out;
+ return;
/* For SGMII, we need to issue a PCS autoneg restart */
reg = rd32(E1000_PCS_LCTL);
@@ -1213,9 +1122,6 @@ static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw)
reg);
}
wr32(E1000_PCS_LCTL, reg);
-
-out:
- return 0;
}
/**
@@ -1229,10 +1135,6 @@ out:
static bool igb_sgmii_active_82575(struct e1000_hw *hw)
{
struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
-
- if (hw->mac.type != e1000_82575 && hw->mac.type != e1000_82576)
- return false;
-
return dev_spec->sgmii_active;
}
@@ -1424,6 +1326,57 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw)
}
/**
+ * igb_set_pcie_completion_timeout - set pci-e completion timeout
+ * @hw: pointer to the HW structure
+ *
+ * The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
+ * however the hardware default for these parts is 500us to 1ms which is less
+ * than the 10ms recommended by the pci-e spec. To address this we need to
+ * increase the value to either 10ms to 200ms for capability version 1 config,
+ * or 16ms to 55ms for version 2.
+ **/
+static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw)
+{
+ u32 gcr = rd32(E1000_GCR);
+ s32 ret_val = 0;
+ u16 pcie_devctl2;
+
+ /* only take action if timeout value is defaulted to 0 */
+ if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
+ goto out;
+
+ /*
+ * if capababilities version is type 1 we can write the
+ * timeout of 10ms to 200ms through the GCR register
+ */
+ if (!(gcr & E1000_GCR_CAP_VER2)) {
+ gcr |= E1000_GCR_CMPL_TMOUT_10ms;
+ goto out;
+ }
+
+ /*
+ * for version 2 capabilities we need to write the config space
+ * directly in order to set the completion timeout value for
+ * 16ms to 55ms
+ */
+ ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+ if (ret_val)
+ goto out;
+
+ pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
+
+ ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
+ &pcie_devctl2);
+out:
+ /* disable completion timeout resend */
+ gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
+
+ wr32(E1000_GCR, gcr);
+ return ret_val;
+}
+
+/**
* igb_vmdq_set_loopback_pf - enable or disable vmdq loopback
* @hw: pointer to the hardware struct
* @enable: state to enter, either enabled or disabled
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index 0f16abab256..8a1e6597061 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -28,10 +28,14 @@
#ifndef _E1000_82575_H_
#define _E1000_82575_H_
-void igb_update_mc_addr_list(struct e1000_hw*, u8*, u32, u32, u32);
extern void igb_shutdown_fiber_serdes_link_82575(struct e1000_hw *hw);
extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
+#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_DEF2 << 8) | \
+ (ID_LED_DEF1_DEF2 << 4) | \
+ (ID_LED_OFF1_ON2))
+
#define E1000_RAR_ENTRIES_82575 16
#define E1000_RAR_ENTRIES_82576 24
diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h
index 3bda3db73f1..c85829355d5 100644
--- a/drivers/net/igb/e1000_defines.h
+++ b/drivers/net/igb/e1000_defines.h
@@ -435,6 +435,12 @@
/* Flow Control */
#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
+/* PCI Express Control */
+#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000
+#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000
+#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000
+#define E1000_GCR_CAP_VER2 0x00040000
+
/* PHY Control Register */
#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */
#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */
@@ -569,9 +575,11 @@
/* PCI/PCI-X/PCI-EX Config space */
#define PCIE_LINK_STATUS 0x12
+#define PCIE_DEVICE_CONTROL2 0x28
#define PCIE_LINK_WIDTH_MASK 0x3F0
#define PCIE_LINK_WIDTH_SHIFT 4
+#define PCIE_DEVICE_CONTROL2_16ms 0x0005
#define PHY_REVISION_MASK 0xFFFFFFF0
#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */
diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h
index 68aac20c31c..119869b1124 100644
--- a/drivers/net/igb/e1000_hw.h
+++ b/drivers/net/igb/e1000_hw.h
@@ -42,6 +42,7 @@ struct e1000_hw;
#define E1000_DEV_ID_82576_SERDES 0x10E7
#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8
#define E1000_DEV_ID_82576_NS 0x150A
+#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D
#define E1000_DEV_ID_82575EB_COPPER 0x10A7
#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9
#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6
@@ -61,8 +62,7 @@ enum e1000_mac_type {
enum e1000_media_type {
e1000_media_type_unknown = 0,
e1000_media_type_copper = 1,
- e1000_media_type_fiber = 2,
- e1000_media_type_internal_serdes = 3,
+ e1000_media_type_internal_serdes = 2,
e1000_num_media_types
};
@@ -137,7 +137,7 @@ enum e1000_rev_polarity {
e1000_rev_polarity_undefined = 0xFF
};
-enum e1000_fc_type {
+enum e1000_fc_mode {
e1000_fc_none = 0,
e1000_fc_rx_pause,
e1000_fc_tx_pause,
@@ -339,6 +339,10 @@ struct e1000_mac_info {
u16 ifs_ratio;
u16 ifs_step_size;
u16 mta_reg_count;
+
+ /* Maximum size of the MTA register table in all supported adapters */
+ #define MAX_MTA_REG 128
+ u32 mta_shadow[MAX_MTA_REG];
u16 rar_entry_count;
u8 forced_speed_duplex;
@@ -425,8 +429,8 @@ struct e1000_fc_info {
u16 pause_time; /* Flow control pause timer */
bool send_xon; /* Flow control send XON */
bool strict_ieee; /* Strict IEEE mode */
- enum e1000_fc_type type; /* Type of flow control */
- enum e1000_fc_type original_type;
+ enum e1000_fc_mode current_mode; /* Type of flow control */
+ enum e1000_fc_mode requested_mode;
};
struct e1000_mbx_operations {
@@ -495,5 +499,7 @@ extern char *igb_get_hw_dev_name(struct e1000_hw *hw);
#else
#define hw_dbg(format, arg...)
#endif
-
#endif
+/* These functions must be implemented by drivers */
+s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
+s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value);
diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c
index 472f3f12484..a0231cd079f 100644
--- a/drivers/net/igb/e1000_mac.c
+++ b/drivers/net/igb/e1000_mac.c
@@ -37,20 +37,6 @@
static s32 igb_set_default_fc(struct e1000_hw *hw);
static s32 igb_set_fc_watermarks(struct e1000_hw *hw);
-static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
-{
- struct igb_adapter *adapter = hw->back;
- u16 cap_offset;
-
- cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
- if (!cap_offset)
- return -E1000_ERR_CONFIG;
-
- pci_read_config_word(adapter->pdev, cap_offset + reg, value);
-
- return 0;
-}
-
/**
* igb_get_bus_info_pcie - Get PCIe bus information
* @hw: pointer to the HW structure
@@ -118,6 +104,31 @@ static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
}
/**
+ * igb_init_rx_addrs - Initialize receive address's
+ * @hw: pointer to the HW structure
+ * @rar_count: receive address registers
+ *
+ * Setups the receive address registers by setting the base receive address
+ * register to the devices MAC address and clearing all the other receive
+ * address registers to 0.
+ **/
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+ u32 i;
+ u8 mac_addr[ETH_ALEN] = {0};
+
+ /* Setup the receive address */
+ hw_dbg("Programming MAC Address into RAR[0]\n");
+
+ hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
+
+ /* Zero out the other (rar_entry_count - 1) receive addresses */
+ hw_dbg("Clearing RAR[1-%u]\n", rar_count-1);
+ for (i = 1; i < rar_count; i++)
+ hw->mac.ops.rar_set(hw, mac_addr, i);
+}
+
+/**
* igb_vfta_set - enable or disable vlan in VLAN filter table
* @hw: pointer to the HW structure
* @vid: VLAN id to add or remove
@@ -275,6 +286,41 @@ void igb_mta_set(struct e1000_hw *hw, u32 hash_value)
}
/**
+ * igb_update_mc_addr_list - Update Multicast addresses
+ * @hw: pointer to the HW structure
+ * @mc_addr_list: array of multicast addresses to program
+ * @mc_addr_count: number of multicast addresses to program
+ *
+ * Updates entire Multicast Table Array.
+ * The caller must have a packed mc_addr_list of multicast addresses.
+ **/
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count)
+{
+ u32 hash_value, hash_bit, hash_reg;
+ int i;
+
+ /* clear mta_shadow */
+ memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));
+
+ /* update mta_shadow from mc_addr_list */
+ for (i = 0; (u32) i < mc_addr_count; i++) {
+ hash_value = igb_hash_mc_addr(hw, mc_addr_list);
+
+ hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+ hash_bit = hash_value & 0x1F;
+
+ hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit);
+ mc_addr_list += (ETH_ALEN);
+ }
+
+ /* replace the entire MTA table */
+ for (i = hw->mac.mta_reg_count - 1; i >= 0; i--)
+ array_wr32(E1000_MTA, i, hw->mac.mta_shadow[i]);
+ wrfl();
+}
+
+/**
* igb_hash_mc_addr - Generate a multicast hash value
* @hw: pointer to the HW structure
* @mc_addr: pointer to a multicast address
@@ -490,18 +536,24 @@ s32 igb_setup_link(struct e1000_hw *hw)
if (igb_check_reset_block(hw))
goto out;
- ret_val = igb_set_default_fc(hw);
- if (ret_val)
- goto out;
+ /*
+ * If requested flow control is set to default, set flow control
+ * based on the EEPROM flow control settings.
+ */
+ if (hw->fc.requested_mode == e1000_fc_default) {
+ ret_val = igb_set_default_fc(hw);
+ if (ret_val)
+ goto out;
+ }
/*
* We want to save off the original Flow Control configuration just
* in case we get disconnected and then reconnected into a different
* hub or switch with different Flow Control capabilities.
*/
- hw->fc.original_type = hw->fc.type;
+ hw->fc.current_mode = hw->fc.requested_mode;
- hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.type);
+ hw_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode);
/* Call the necessary media_type subroutine to configure the link. */
ret_val = hw->mac.ops.setup_physical_interface(hw);
@@ -568,7 +620,7 @@ static s32 igb_set_fc_watermarks(struct e1000_hw *hw)
* ability to transmit pause frames is not enabled, then these
* registers will be set to 0.
*/
- if (hw->fc.type & e1000_fc_tx_pause) {
+ if (hw->fc.current_mode & e1000_fc_tx_pause) {
/*
* We need to set up the Receive Threshold high and low water
* marks as well as (optionally) enabling the transmission of
@@ -615,12 +667,12 @@ static s32 igb_set_default_fc(struct e1000_hw *hw)
}
if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
- hw->fc.type = e1000_fc_none;
+ hw->fc.requested_mode = e1000_fc_none;
else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
NVM_WORD0F_ASM_DIR)
- hw->fc.type = e1000_fc_tx_pause;
+ hw->fc.requested_mode = e1000_fc_tx_pause;
else
- hw->fc.type = e1000_fc_full;
+ hw->fc.requested_mode = e1000_fc_full;
out:
return ret_val;
@@ -650,7 +702,7 @@ s32 igb_force_mac_fc(struct e1000_hw *hw)
* receive flow control.
*
* The "Case" statement below enables/disable flow control
- * according to the "hw->fc.type" parameter.
+ * according to the "hw->fc.current_mode" parameter.
*
* The possible values of the "fc" parameter are:
* 0: Flow control is completely disabled
@@ -661,9 +713,9 @@ s32 igb_force_mac_fc(struct e1000_hw *hw)
* 3: Both Rx and TX flow control (symmetric) is enabled.
* other: No other values should be possible at this point.
*/
- hw_dbg("hw->fc.type = %u\n", hw->fc.type);
+ hw_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode);
- switch (hw->fc.type) {
+ switch (hw->fc.current_mode) {
case e1000_fc_none:
ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
break;
@@ -713,8 +765,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* configuration of the MAC to match the "fc" parameter.
*/
if (mac->autoneg_failed) {
- if (hw->phy.media_type == e1000_media_type_fiber ||
- hw->phy.media_type == e1000_media_type_internal_serdes)
+ if (hw->phy.media_type == e1000_media_type_internal_serdes)
ret_val = igb_force_mac_fc(hw);
} else {
if (hw->phy.media_type == e1000_media_type_copper)
@@ -812,11 +863,11 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* ONLY. Hence, we must now check to see if we need to
* turn OFF the TRANSMISSION of PAUSE frames.
*/
- if (hw->fc.original_type == e1000_fc_full) {
- hw->fc.type = e1000_fc_full;
+ if (hw->fc.requested_mode == e1000_fc_full) {
+ hw->fc.current_mode = e1000_fc_full;
hw_dbg("Flow Control = FULL.\r\n");
} else {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = "
"RX PAUSE frames only.\r\n");
}
@@ -833,7 +884,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc.type = e1000_fc_tx_pause;
+ hw->fc.current_mode = e1000_fc_tx_pause;
hw_dbg("Flow Control = TX PAUSE frames only.\r\n");
}
/*
@@ -848,7 +899,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
}
/*
@@ -872,13 +923,13 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
* be asked to delay transmission of packets than asking
* our link partner to pause transmission of frames.
*/
- else if ((hw->fc.original_type == e1000_fc_none ||
- hw->fc.original_type == e1000_fc_tx_pause) ||
+ else if ((hw->fc.requested_mode == e1000_fc_none ||
+ hw->fc.requested_mode == e1000_fc_tx_pause) ||
hw->fc.strict_ieee) {
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
hw_dbg("Flow Control = NONE.\r\n");
} else {
- hw->fc.type = e1000_fc_rx_pause;
+ hw->fc.current_mode = e1000_fc_rx_pause;
hw_dbg("Flow Control = RX PAUSE frames only.\r\n");
}
@@ -894,7 +945,7 @@ s32 igb_config_fc_after_link_up(struct e1000_hw *hw)
}
if (duplex == HALF_DUPLEX)
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
/*
* Now we call a subroutine to actually force the MAC
@@ -1065,9 +1116,17 @@ static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data)
goto out;
}
- if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
- *data = ID_LED_DEFAULT;
-
+ if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
+ switch(hw->phy.media_type) {
+ case e1000_media_type_internal_serdes:
+ *data = ID_LED_DEFAULT_82575_SERDES;
+ break;
+ case e1000_media_type_copper:
+ default:
+ *data = ID_LED_DEFAULT;
+ break;
+ }
+ }
out:
return ret_val;
}
@@ -1161,22 +1220,16 @@ s32 igb_blink_led(struct e1000_hw *hw)
u32 ledctl_blink = 0;
u32 i;
- 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)
- * 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));
- }
+ /*
+ * 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));
wr32(E1000_LEDCTL, ledctl_blink);
@@ -1191,15 +1244,7 @@ s32 igb_blink_led(struct e1000_hw *hw)
**/
s32 igb_led_off(struct e1000_hw *hw)
{
- u32 ctrl;
-
switch (hw->phy.media_type) {
- case e1000_media_type_fiber:
- ctrl = rd32(E1000_CTRL);
- ctrl |= E1000_CTRL_SWDPIN0;
- ctrl |= E1000_CTRL_SWDPIO0;
- wr32(E1000_CTRL, ctrl);
- break;
case e1000_media_type_copper:
wr32(E1000_LEDCTL, hw->mac.ledctl_mode1);
break;
diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h
index 1d690b4c9ae..7518af8cbbf 100644
--- a/drivers/net/igb/e1000_mac.h
+++ b/drivers/net/igb/e1000_mac.h
@@ -51,6 +51,8 @@ s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed,
u16 *duplex);
s32 igb_id_led_init(struct e1000_hw *hw);
s32 igb_led_off(struct e1000_hw *hw);
+void igb_update_mc_addr_list(struct e1000_hw *hw,
+ u8 *mc_addr_list, u32 mc_addr_count);
s32 igb_setup_link(struct e1000_hw *hw);
s32 igb_validate_mdi_setting(struct e1000_hw *hw);
s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
@@ -60,6 +62,7 @@ void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
void igb_clear_vfta(struct e1000_hw *hw);
s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
void igb_config_collision_dist(struct e1000_hw *hw);
+void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
void igb_put_hw_semaphore(struct e1000_hw *hw);
void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c
index f50fac25be4..c1f4da63042 100644
--- a/drivers/net/igb/e1000_phy.c
+++ b/drivers/net/igb/e1000_phy.c
@@ -735,7 +735,7 @@ static s32 igb_phy_setup_autoneg(struct e1000_hw *hw)
* other: No software override. The flow control configuration
* in the EEPROM is used.
*/
- switch (hw->fc.type) {
+ switch (hw->fc.current_mode) {
case e1000_fc_none:
/*
* Flow control (RX & TX) is completely disabled by a
@@ -992,7 +992,7 @@ static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw,
u32 ctrl;
/* Turn off flow control when forcing speed/duplex */
- hw->fc.type = e1000_fc_none;
+ hw->fc.current_mode = e1000_fc_none;
/* Force speed/duplex on the mac */
ctrl = rd32(E1000_CTRL);
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index 6e5924511e4..345d1442d6d 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -305,6 +305,7 @@ enum {
#define E1000_CCMCTL 0x05B48 /* CCM Control Register */
#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */
#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */
+#define E1000_GCR 0x05B00 /* PCI-Ex Control */
#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */
#define E1000_SWSM 0x05B50 /* SW Semaphore */
#define E1000_FWSM 0x05B54 /* FW Semaphore */
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index 9598ac09f4b..114ccab1f2b 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -168,8 +168,7 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->duplex = -1;
}
- ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
- hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ ecmd->autoneg = hw->mac.autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
return 0;
}
@@ -191,23 +190,20 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
if (ecmd->autoneg == AUTONEG_ENABLE) {
hw->mac.autoneg = 1;
- if (hw->phy.media_type == e1000_media_type_fiber)
- hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
- ADVERTISED_FIBRE |
- ADVERTISED_Autoneg;
- else
- hw->phy.autoneg_advertised = ecmd->advertising |
- ADVERTISED_TP |
- ADVERTISED_Autoneg;
+ hw->phy.autoneg_advertised = ecmd->advertising |
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
ecmd->advertising = hw->phy.autoneg_advertised;
- } else
+ if (adapter->fc_autoneg)
+ hw->fc.requested_mode = e1000_fc_default;
+ } else {
if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
clear_bit(__IGB_RESETTING, &adapter->state);
return -EINVAL;
}
+ }
/* reset the link */
-
if (netif_running(adapter->netdev)) {
igb_down(adapter);
igb_up(adapter);
@@ -227,11 +223,11 @@ static void igb_get_pauseparam(struct net_device *netdev,
pause->autoneg =
(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
- if (hw->fc.type == e1000_fc_rx_pause)
+ if (hw->fc.current_mode == e1000_fc_rx_pause)
pause->rx_pause = 1;
- else if (hw->fc.type == e1000_fc_tx_pause)
+ else if (hw->fc.current_mode == e1000_fc_tx_pause)
pause->tx_pause = 1;
- else if (hw->fc.type == e1000_fc_full) {
+ else if (hw->fc.current_mode == e1000_fc_full) {
pause->rx_pause = 1;
pause->tx_pause = 1;
}
@@ -249,26 +245,28 @@ static int igb_set_pauseparam(struct net_device *netdev,
while (test_and_set_bit(__IGB_RESETTING, &adapter->state))
msleep(1);
- if (pause->rx_pause && pause->tx_pause)
- hw->fc.type = e1000_fc_full;
- else if (pause->rx_pause && !pause->tx_pause)
- hw->fc.type = e1000_fc_rx_pause;
- else if (!pause->rx_pause && pause->tx_pause)
- hw->fc.type = e1000_fc_tx_pause;
- else if (!pause->rx_pause && !pause->tx_pause)
- hw->fc.type = e1000_fc_none;
-
- hw->fc.original_type = hw->fc.type;
-
if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+ hw->fc.requested_mode = e1000_fc_default;
if (netif_running(adapter->netdev)) {
igb_down(adapter);
igb_up(adapter);
} else
igb_reset(adapter);
- } else
- retval = ((hw->phy.media_type == e1000_media_type_fiber) ?
- igb_setup_link(hw) : igb_force_mac_fc(hw));
+ } else {
+ if (pause->rx_pause && pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_full;
+ else if (pause->rx_pause && !pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_rx_pause;
+ else if (!pause->rx_pause && pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_tx_pause;
+ else if (!pause->rx_pause && !pause->tx_pause)
+ hw->fc.requested_mode = e1000_fc_none;
+
+ hw->fc.current_mode = hw->fc.requested_mode;
+
+ retval = ((hw->phy.media_type == e1000_media_type_copper) ?
+ igb_force_mac_fc(hw) : igb_setup_link(hw));
+ }
clear_bit(__IGB_RESETTING, &adapter->state);
return retval;
@@ -1483,8 +1481,7 @@ static int igb_setup_loopback_test(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 reg;
- if (hw->phy.media_type == e1000_media_type_fiber ||
- hw->phy.media_type == e1000_media_type_internal_serdes) {
+ if (hw->phy.media_type == e1000_media_type_internal_serdes) {
reg = rd32(E1000_RCTL);
reg |= E1000_RCTL_LBM_TCVR;
wr32(E1000_RCTL, reg);
@@ -1843,7 +1840,6 @@ static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct igb_adapter *adapter = netdev_priv(netdev);
- struct e1000_hw *hw = &adapter->hw;
if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
return -EOPNOTSUPP;
@@ -1852,11 +1848,6 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
!device_can_wakeup(&adapter->pdev->dev))
return wol->wolopts ? -EOPNOTSUPP : 0;
- switch (hw->device_id) {
- default:
- break;
- }
-
/* these settings will always override what we currently have */
adapter->wol = 0;
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index adb09d32625..fb327351758 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -65,6 +65,7 @@ static struct pci_device_id igb_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
@@ -127,7 +128,7 @@ static void igb_restore_vlan(struct igb_adapter *);
static void igb_ping_all_vfs(struct igb_adapter *);
static void igb_msg_task(struct igb_adapter *);
static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
-static void igb_set_mc_list_pools(struct igb_adapter *, int, u16);
+static inline void igb_set_rah_pool(struct e1000_hw *, int , int);
static void igb_vmm_control(struct igb_adapter *);
static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
@@ -1129,7 +1130,7 @@ void igb_reset(struct igb_adapter *adapter)
}
fc->pause_time = 0xFFFF;
fc->send_xon = 1;
- fc->type = fc->original_type;
+ fc->current_mode = fc->requested_mode;
/* disable receive for all VFs and wait one second */
if (adapter->vfs_allocated_count) {
@@ -1426,8 +1427,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,
hw->mac.autoneg = true;
hw->phy.autoneg_advertised = 0x2f;
- hw->fc.original_type = e1000_fc_default;
- hw->fc.type = e1000_fc_default;
+ hw->fc.requested_mode = e1000_fc_default;
+ hw->fc.current_mode = e1000_fc_default;
adapter->itr_setting = IGB_DEFAULT_ITR;
adapter->itr = IGB_START_ITR;
@@ -2535,7 +2536,6 @@ static void igb_set_multi(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- struct e1000_mac_info *mac = &hw->mac;
struct dev_mc_list *mc_ptr;
u8 *mta_list = NULL;
u32 rctl;
@@ -2558,13 +2558,18 @@ static void igb_set_multi(struct net_device *netdev)
}
wr32(E1000_RCTL, rctl);
- if (netdev->mc_count) {
- mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
- if (!mta_list) {
- dev_err(&adapter->pdev->dev,
- "failed to allocate multicast filter list\n");
- return;
- }
+ if (!netdev->mc_count) {
+ /* nothing to program, so clear mc list */
+ igb_update_mc_addr_list(hw, NULL, 0);
+ igb_restore_vf_multicasts(adapter);
+ return;
+ }
+
+ mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
+ if (!mta_list) {
+ dev_err(&adapter->pdev->dev,
+ "failed to allocate multicast filter list\n");
+ return;
}
/* The shared function expects a packed array of only addresses. */
@@ -2576,14 +2581,9 @@ static void igb_set_multi(struct net_device *netdev)
memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
mc_ptr = mc_ptr->next;
}
- igb_update_mc_addr_list(hw, mta_list, i,
- adapter->vfs_allocated_count + 1,
- mac->rar_entry_count);
-
- igb_set_mc_list_pools(adapter, i, mac->rar_entry_count);
- igb_restore_vf_multicasts(adapter);
-
+ igb_update_mc_addr_list(hw, mta_list, i);
kfree(mta_list);
+ igb_restore_vf_multicasts(adapter);
}
/* Need to wait a few seconds after link up to get diagnostic information from
@@ -2618,10 +2618,6 @@ static bool igb_has_link(struct igb_adapter *adapter)
link_active = true;
}
break;
- case e1000_media_type_fiber:
- ret_val = hw->mac.ops.check_for_link(hw);
- link_active = !!(rd32(E1000_STATUS) & E1000_STATUS_LU);
- break;
case e1000_media_type_internal_serdes:
ret_val = hw->mac.ops.check_for_link(hw);
link_active = hw->mac.serdes_has_link;
@@ -4542,6 +4538,20 @@ static inline void igb_rx_checksum_adv(struct igb_adapter *adapter,
adapter->hw_csum_good++;
}
+static inline u16 igb_get_hlen(struct igb_adapter *adapter,
+ union e1000_adv_rx_desc *rx_desc)
+{
+ /* HW will not DMA in data larger than the given buffer, even if it
+ * parses the (NFS, of course) header to be larger. In that case, it
+ * fills the header buffer and spills the rest into the page.
+ */
+ u16 hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
+ E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
+ if (hlen > adapter->rx_ps_hdr_size)
+ hlen = adapter->rx_ps_hdr_size;
+ return hlen;
+}
+
static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
int *work_done, int budget)
{
@@ -4556,7 +4566,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
int cleaned_count = 0;
unsigned int total_bytes = 0, total_packets = 0;
unsigned int i;
- u32 length, hlen, staterr;
+ u32 staterr;
+ u16 length;
i = rx_ring->next_to_clean;
buffer_info = &rx_ring->buffer_info[i];
@@ -4593,17 +4604,8 @@ static bool igb_clean_rx_irq_adv(struct igb_ring *rx_ring,
goto send_up;
}
- /* HW will not DMA in data larger than the given buffer, even
- * if it parses the (NFS, of course) header to be larger. In
- * that case, it fills the header buffer and spills the rest
- * into the page.
- */
- hlen = (le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info) &
- E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT;
- if (hlen > adapter->rx_ps_hdr_size)
- hlen = adapter->rx_ps_hdr_size;
-
- if (!skb_shinfo(skb)->nr_frags) {
+ if (buffer_info->dma) {
+ u16 hlen = igb_get_hlen(adapter, rx_desc);
pci_unmap_single(pdev, buffer_info->dma,
adapter->rx_ps_hdr_size,
PCI_DMA_FROMDEVICE);
@@ -5033,6 +5035,34 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
}
}
+s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+ struct igb_adapter *adapter = hw->back;
+ u16 cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -E1000_ERR_CONFIG;
+
+ pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+ return 0;
+}
+
+s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value)
+{
+ struct igb_adapter *adapter = hw->back;
+ u16 cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -E1000_ERR_CONFIG;
+
+ pci_write_config_word(adapter->pdev, cap_offset + reg, *value);
+
+ return 0;
+}
+
static void igb_vlan_rx_register(struct net_device *netdev,
struct vlan_group *grp)
{
@@ -5136,14 +5166,6 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
mac->autoneg = 0;
- /* Fiber NICs only allow 1000 gbps Full duplex */
- if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
- spddplx != (SPEED_1000 + DUPLEX_FULL)) {
- dev_err(&adapter->pdev->dev,
- "Unsupported Speed/Duplex configuration\n");
- return -EINVAL;
- }
-
switch (spddplx) {
case SPEED_10 + DUPLEX_HALF:
mac->forced_speed_duplex = ADVERTISE_10_HALF;
@@ -5452,19 +5474,6 @@ static void igb_io_resume(struct pci_dev *pdev)
igb_get_hw_control(adapter);
}
-static void igb_set_mc_list_pools(struct igb_adapter *adapter,
- int entry_count, u16 total_rar_filters)
-{
- struct e1000_hw *hw = &adapter->hw;
- int i = adapter->vfs_allocated_count + 1;
-
- if ((i + entry_count) < total_rar_filters)
- total_rar_filters = i + entry_count;
-
- for (; i < total_rar_filters; i++)
- igb_set_rah_pool(hw, adapter->vfs_allocated_count, i);
-}
-
static int igb_set_vf_mac(struct igb_adapter *adapter,
int vf, unsigned char *mac_addr)
{
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 2bc9d63027d..926c31b4726 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -149,7 +149,6 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
bufsz = adapter->rx_ps_hdr_size;
else
bufsz = adapter->rx_buffer_len;
- bufsz += NET_IP_ALIGN;
while (cleaned_count--) {
rx_desc = IGBVF_RX_DESC_ADV(*rx_ring, i);
@@ -173,7 +172,7 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring,
}
if (!buffer_info->skb) {
- skb = netdev_alloc_skb(netdev, bufsz);
+ skb = netdev_alloc_skb(netdev, bufsz + NET_IP_ALIGN);
if (!skb) {
adapter->alloc_rx_buff_failed++;
goto no_buffers;
@@ -286,7 +285,7 @@ static bool igbvf_clean_rx_irq(struct igbvf_adapter *adapter,
if (!skb_shinfo(skb)->nr_frags) {
pci_unmap_single(pdev, buffer_info->dma,
- adapter->rx_ps_hdr_size + NET_IP_ALIGN,
+ adapter->rx_ps_hdr_size,
PCI_DMA_FROMDEVICE);
skb_put(skb, hlen);
}
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index e3cfefab670..8ec15ab8c8c 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -1515,7 +1515,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irq(&ip->ioc3_lock);
- return 0;
+ return NETDEV_TX_OK;
}
static void ioc3_timeout(struct net_device *dev)
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index ad179558002..f0d0cea6e32 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -1466,7 +1466,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -1577,7 +1577,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
IRDA_DEBUG(1, "%s(), ----------------- End ------------------\n", __func__ );
- return 0;
+ return NETDEV_TX_OK;
}
@@ -1966,10 +1966,10 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ );
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.sir_base;
@@ -1991,7 +1991,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -2015,7 +2015,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ );
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index c4361d46659..22baf65e156 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -502,7 +502,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
aup->newspeed = 0;
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
ptxd = aup->tx_ring[aup->tx_head];
@@ -555,7 +555,7 @@ static int au1k_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
aup->tx_head = (aup->tx_head + 1) & (NUM_IR_DESC - 1);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 9a0346e751a..e4e905698dc 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -981,7 +981,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
self = netdev_priv(dev);
- IRDA_ASSERT (self != NULL, return 0; );
+ IRDA_ASSERT (self != NULL, return NETDEV_TX_OK; );
IRDA_DEBUG (1, "%s.tx:%x(%x)%x\n", __func__
,skb->len,self->txpending,INB (OBOE_ENABLEH));
@@ -1021,7 +1021,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
{
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* True packet, go on, but */
/* do not accept anything before change speed execution */
@@ -1036,7 +1036,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
toshoboe_setbaud (self);
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -1143,7 +1143,7 @@ dumpbufs(skb->data,skb->len,'>');
spin_unlock_irqrestore(&self->spinlock, flags);
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*interrupt handler */
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 0c0831c03f6..6a1aa7a40fe 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -534,7 +534,7 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
}
spin_unlock_irqrestore(&self->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop:
/* Drop silently the skb and exit */
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index 45fd9c1eb34..51ca89c9a0b 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1365,7 +1365,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.fir_base;
@@ -1397,7 +1397,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -1424,7 +1424,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
@@ -1467,7 +1467,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else {
/* Change speed after current frame */
self->new_speed = speed;
@@ -1554,7 +1554,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index 3376a4f39e0..e76a083f901 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -504,7 +504,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
pxa_irda_set_speed(si, speed);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -539,7 +539,7 @@ static int pxa_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 2aeb2e6aec1..70e6acc597b 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -667,7 +667,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
sa1100_irda_set_speed(si, speed);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (!IS_FIR(si)) {
@@ -715,7 +715,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static int
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index fd0796c3db3..71dce20e62b 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -590,7 +590,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
int err;
s32 speed;
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
netif_stop_queue(ndev);
@@ -621,7 +621,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
dev->new_speed = speed;
}
@@ -668,7 +668,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
}
spin_unlock_irqrestore(&dev->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* called from network layer with rtnl hold */
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index d0797adb5f8..15f8a7f8160 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -886,10 +886,10 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
IRDA_DEBUG(1, "%s\n", __func__);
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
netif_stop_queue(dev);
@@ -914,7 +914,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
self->new_speed = speed;
}
@@ -935,7 +935,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -1190,9 +1190,9 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
s32 speed;
int mtt;
- IRDA_ASSERT(dev != NULL, return 0;);
+ IRDA_ASSERT(dev != NULL, return NETDEV_TX_OK;);
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
netif_stop_queue(dev);
@@ -1210,7 +1210,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
smsc_ircc_change_speed(self, speed);
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
self->new_speed = speed;
@@ -1242,7 +1242,7 @@ static int smsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 8e5e45caf2f..c475b23091b 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -578,7 +578,7 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
dev_kfree_skb(skb);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 864798502ff..36a60748447 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -832,7 +832,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
__u32 speed;
self = netdev_priv(dev);
- IRDA_ASSERT(self != NULL, return 0;);
+ IRDA_ASSERT(self != NULL, return NETDEV_TX_OK;);
iobase = self->io.fir_base;
netif_stop_queue(dev);
@@ -844,7 +844,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
via_ircc_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -892,7 +892,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb,
dev->trans_start = jiffies;
spin_unlock_irqrestore(&self->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
@@ -907,7 +907,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
iobase = self->io.fir_base;
if (self->st_fifo.len)
- return 0;
+ return NETDEV_TX_OK;
if (self->chip_id == 0x3076)
iodelay(1500);
else
@@ -919,7 +919,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
via_ircc_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -940,7 +940,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
dev->trans_start = jiffies;
dev_kfree_skb(skb);
spin_unlock_irqrestore(&self->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index ac0e4b6b6b6..08e26f1297b 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -915,7 +915,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
*/
spin_unlock_irqrestore(&idev->lock, flags);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* sanity checks - simply drop the packet */
@@ -1044,7 +1044,7 @@ static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
}
spin_unlock_irqrestore(&idev->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop_unlock:
spin_unlock_irqrestore(&idev->lock, flags);
@@ -1058,7 +1058,7 @@ drop:
* packet for later retry of transmission - which isn't exactly
* what we want after we've just called dev_kfree_skb_any ;-)
*/
- return 0;
+ return NETDEV_TX_OK;
}
static void vlsi_tx_interrupt(struct net_device *ndev)
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index d0883835b0c..49ef76320f5 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -516,7 +516,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
w83977af_change_speed(self, speed);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else
self->new_speed = speed;
}
@@ -576,7 +576,7 @@ static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev)
/* Restore set register */
outb(set, iobase+SSR);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index d12377b8435..9706e64e367 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -468,7 +468,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
#if TX_RING
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index e44215cb188..e36e951cbc6 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -1205,7 +1205,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
if ( ! ((1 << rlp) & port->lpar_map) ) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
lpmask = 1 << rlp;
@@ -1217,7 +1217,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* You must hold the connection's lock when you call this function. */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 9c897cf86b9..eb917f16027 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1459,7 +1459,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (skb->len <= 0) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (unlikely(ixgb_maybe_stop_tx(netdev, &adapter->tx_ring,
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index e11d83d5852..62b6c028ae8 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -231,10 +231,6 @@ struct ixgbe_q_vector {
#define IXGBE_TX_CTXTDESC_ADV(R, i) \
(&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
-#define IXGBE_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
-#define IXGBE_TX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_tx_desc)
-#define IXGBE_RX_DESC(R, i) IXGBE_GET_DESC(R, i, ixgbe_legacy_rx_desc)
-
#define IXGBE_MAX_JUMBO_FRAME_SIZE 16128
#ifdef IXGBE_FCOE
/* Use 3K as the baby jumbo frame size for FCoE */
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index b9923047ce1..ed0bb3b2025 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -269,6 +269,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
media_type = ixgbe_media_type_fiber;
break;
case IXGBE_DEV_ID_82598AT:
+ case IXGBE_DEV_ID_82598AT2:
media_type = ixgbe_media_type_copper;
break;
default:
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 79144e950a3..c6db9a04187 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -1440,7 +1440,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
goto err_nomem;
}
- tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc);
+ tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
tx_ring->size = ALIGN(tx_ring->size, 4096);
if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
&tx_ring->dma))) {
@@ -1454,7 +1454,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0),
((u64) tx_ring->dma >> 32));
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0),
- tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc));
+ tx_ring->count * sizeof(union ixgbe_adv_tx_desc));
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0);
@@ -1472,7 +1472,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data);
for (i = 0; i < tx_ring->count; i++) {
- struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i);
+ union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
struct sk_buff *skb;
unsigned int size = 1024;
@@ -1486,13 +1486,18 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
tx_ring->tx_buffer_info[i].length = skb->len;
tx_ring->tx_buffer_info[i].dma =
pci_map_single(pdev, skb->data, skb->len,
- PCI_DMA_TODEVICE);
- desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
- desc->lower.data = cpu_to_le32(skb->len);
- desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
- IXGBE_TXD_CMD_IFCS |
- IXGBE_TXD_CMD_RS);
- desc->upper.data = 0;
+ PCI_DMA_TODEVICE);
+ desc->read.buffer_addr =
+ cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
+ desc->read.cmd_type_len = cpu_to_le32(skb->len);
+ desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
+ IXGBE_TXD_CMD_IFCS |
+ IXGBE_TXD_CMD_RS);
+ desc->read.olinfo_status = 0;
+ if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ desc->read.olinfo_status |=
+ (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
}
/* Setup Rx Descriptor ring and Rx buffers */
@@ -1508,7 +1513,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
goto err_nomem;
}
- rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc);
+ rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
rx_ring->size = ALIGN(rx_ring->size, 4096);
if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
&rx_ring->dma))) {
@@ -1566,8 +1571,8 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl);
for (i = 0; i < rx_ring->count; i++) {
- struct ixgbe_legacy_rx_desc *rx_desc =
- IXGBE_RX_DESC(*rx_ring, i);
+ union ixgbe_adv_rx_desc *rx_desc =
+ IXGBE_RX_DESC_ADV(*rx_ring, i);
struct sk_buff *skb;
skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
@@ -1580,7 +1585,7 @@ static int ixgbe_setup_desc_rings(struct ixgbe_adapter *adapter)
rx_ring->rx_buffer_info[i].dma =
pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048,
PCI_DMA_FROMDEVICE);
- rx_desc->buffer_addr =
+ rx_desc->read.pkt_addr =
cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
memset(skb->data, 0x00, skb->len);
}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 110c65ab5cb..44adc986282 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -49,7 +49,7 @@ char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver";
-#define DRV_VERSION "2.0.34-k2"
+#define DRV_VERSION "2.0.37-k2"
const char ixgbe_driver_version[] = DRV_VERSION;
static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation.";
@@ -75,6 +75,8 @@ static struct pci_device_id ixgbe_pci_tbl[] = {
board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT),
board_82598 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT2),
+ board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
board_82598 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT),
@@ -4658,13 +4660,13 @@ static void ixgbe_watchdog_task(struct work_struct *work)
if (hw->mac.type == ixgbe_mac_82599EB) {
u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
- flow_rx = (mflcn & IXGBE_MFLCN_RFCE);
- flow_tx = (fccfg & IXGBE_FCCFG_TFCE_802_3X);
+ flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
+ flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
} else {
u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
- flow_rx = (frctl & IXGBE_FCTRL_RFCE);
- flow_tx = (rmcs & IXGBE_RMCS_TFCE_802_3X);
+ flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
+ flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
}
printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index fa87309dc08..17ee3890a0a 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -42,6 +42,7 @@
#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
#define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB
#define IXGBE_DEV_ID_82598AT 0x10C8
+#define IXGBE_DEV_ID_82598AT2 0x150B
#define IXGBE_DEV_ID_82598EB_CX4 0x10DD
#define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1
@@ -1893,27 +1894,6 @@ enum ixgbe_fdir_pballoc_type {
#define IXGBE_FDIR_INIT_DONE_POLL 10
#define IXGBE_FDIRCMD_CMD_POLL 10
-/* Transmit Descriptor - Legacy */
-struct ixgbe_legacy_tx_desc {
- u64 buffer_addr; /* Address of the descriptor's data buffer */
- union {
- __le32 data;
- struct {
- __le16 length; /* Data buffer length */
- u8 cso; /* Checksum offset */
- u8 cmd; /* Descriptor control */
- } flags;
- } lower;
- union {
- __le32 data;
- struct {
- u8 status; /* Descriptor status */
- u8 css; /* Checksum start */
- __le16 vlan;
- } fields;
- } upper;
-};
-
/* Transmit Descriptor - Advanced */
union ixgbe_adv_tx_desc {
struct {
@@ -1928,16 +1908,6 @@ union ixgbe_adv_tx_desc {
} wb;
};
-/* Receive Descriptor - Legacy */
-struct ixgbe_legacy_rx_desc {
- __le64 buffer_addr; /* Address of the descriptor's data buffer */
- __le16 length; /* Length of data DMAed into data buffer */
- __le16 csum; /* Packet checksum */
- u8 status; /* Descriptor status */
- u8 errors; /* Descriptor Errors */
- __le16 vlan;
-};
-
/* Receive Descriptor - Advanced */
union ixgbe_adv_rx_desc {
struct {
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 2a0174b62e9..588b44d944c 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -45,7 +45,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len > PAGE_SIZE)) {
/* @@@ Count drops. */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
entry = tx_pointer;
@@ -69,7 +69,7 @@ static int ixpdev_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
local_irq_enable();
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 2f286091394..ec337b502fd 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -108,7 +108,7 @@ static const struct net_device_ops sonic_netdev_ops = {
.ndo_set_mac_address = eth_mac_addr,
};
-static int __init sonic_probe1(struct net_device *dev)
+static int __devinit sonic_probe1(struct net_device *dev)
{
static unsigned version_printed;
unsigned int silicon_revision;
@@ -211,7 +211,7 @@ out:
* Probe for a SONIC ethernet controller on a Mips Jazz board.
* Actually probing is superfluous but we're paranoid.
*/
-static int __init jazz_sonic_probe(struct platform_device *pdev)
+static int __devinit jazz_sonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 1e3c63d67b9..e7068c7cd62 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -322,20 +322,6 @@ jme_stop_irq(struct jme_adapter *jme)
jwrite32f(jme, JME_IENC, INTR_ENABLE);
}
-static inline void
-jme_enable_shadow(struct jme_adapter *jme)
-{
- jwrite32(jme,
- JME_SHBA_LO,
- ((u32)jme->shadow_dma & ~((u32)0x1F)) | SHBA_POSTEN);
-}
-
-static inline void
-jme_disable_shadow(struct jme_adapter *jme)
-{
- jwrite32(jme, JME_SHBA_LO, 0x0);
-}
-
static u32
jme_linkstat_from_phy(struct jme_adapter *jme)
{
@@ -522,12 +508,8 @@ jme_setup_tx_resources(struct jme_adapter *jme)
&(txring->dmaalloc),
GFP_ATOMIC);
- if (!txring->alloc) {
- txring->desc = NULL;
- txring->dmaalloc = 0;
- txring->dma = 0;
- return -ENOMEM;
- }
+ if (!txring->alloc)
+ goto err_set_null;
/*
* 16 Bytes align
@@ -539,6 +521,11 @@ jme_setup_tx_resources(struct jme_adapter *jme)
atomic_set(&txring->next_to_clean, 0);
atomic_set(&txring->nr_free, jme->tx_ring_size);
+ txring->bufinf = kmalloc(sizeof(struct jme_buffer_info) *
+ jme->tx_ring_size, GFP_ATOMIC);
+ if (unlikely(!(txring->bufinf)))
+ goto err_free_txring;
+
/*
* Initialize Transmit Descriptors
*/
@@ -547,6 +534,20 @@ jme_setup_tx_resources(struct jme_adapter *jme)
sizeof(struct jme_buffer_info) * jme->tx_ring_size);
return 0;
+
+err_free_txring:
+ dma_free_coherent(&(jme->pdev->dev),
+ TX_RING_ALLOC_SIZE(jme->tx_ring_size),
+ txring->alloc,
+ txring->dmaalloc);
+
+err_set_null:
+ txring->desc = NULL;
+ txring->dmaalloc = 0;
+ txring->dma = 0;
+ txring->bufinf = NULL;
+
+ return -ENOMEM;
}
static void
@@ -554,19 +555,22 @@ jme_free_tx_resources(struct jme_adapter *jme)
{
int i;
struct jme_ring *txring = &(jme->txring[0]);
- struct jme_buffer_info *txbi = txring->bufinf;
+ struct jme_buffer_info *txbi;
if (txring->alloc) {
- for (i = 0 ; i < jme->tx_ring_size ; ++i) {
- txbi = txring->bufinf + i;
- if (txbi->skb) {
- dev_kfree_skb(txbi->skb);
- txbi->skb = NULL;
+ if (txring->bufinf) {
+ for (i = 0 ; i < jme->tx_ring_size ; ++i) {
+ txbi = txring->bufinf + i;
+ if (txbi->skb) {
+ dev_kfree_skb(txbi->skb);
+ txbi->skb = NULL;
+ }
+ txbi->mapping = 0;
+ txbi->len = 0;
+ txbi->nr_desc = 0;
+ txbi->start_xmit = 0;
}
- txbi->mapping = 0;
- txbi->len = 0;
- txbi->nr_desc = 0;
- txbi->start_xmit = 0;
+ kfree(txring->bufinf);
}
dma_free_coherent(&(jme->pdev->dev),
@@ -578,11 +582,11 @@ jme_free_tx_resources(struct jme_adapter *jme)
txring->desc = NULL;
txring->dmaalloc = 0;
txring->dma = 0;
+ txring->bufinf = NULL;
}
txring->next_to_use = 0;
atomic_set(&txring->next_to_clean, 0);
atomic_set(&txring->nr_free, 0);
-
}
static inline void
@@ -653,7 +657,7 @@ jme_disable_tx_engine(struct jme_adapter *jme)
static void
jme_set_clean_rxdesc(struct jme_adapter *jme, int i)
{
- struct jme_ring *rxring = jme->rxring;
+ struct jme_ring *rxring = &(jme->rxring[0]);
register struct rxdesc *rxdesc = rxring->desc;
struct jme_buffer_info *rxbi = rxring->bufinf;
rxdesc += i;
@@ -720,8 +724,11 @@ jme_free_rx_resources(struct jme_adapter *jme)
struct jme_ring *rxring = &(jme->rxring[0]);
if (rxring->alloc) {
- for (i = 0 ; i < jme->rx_ring_size ; ++i)
- jme_free_rx_buf(jme, i);
+ if (rxring->bufinf) {
+ for (i = 0 ; i < jme->rx_ring_size ; ++i)
+ jme_free_rx_buf(jme, i);
+ kfree(rxring->bufinf);
+ }
dma_free_coherent(&(jme->pdev->dev),
RX_RING_ALLOC_SIZE(jme->rx_ring_size),
@@ -731,6 +738,7 @@ jme_free_rx_resources(struct jme_adapter *jme)
rxring->desc = NULL;
rxring->dmaalloc = 0;
rxring->dma = 0;
+ rxring->bufinf = NULL;
}
rxring->next_to_use = 0;
atomic_set(&rxring->next_to_clean, 0);
@@ -746,12 +754,8 @@ jme_setup_rx_resources(struct jme_adapter *jme)
RX_RING_ALLOC_SIZE(jme->rx_ring_size),
&(rxring->dmaalloc),
GFP_ATOMIC);
- if (!rxring->alloc) {
- rxring->desc = NULL;
- rxring->dmaalloc = 0;
- rxring->dma = 0;
- return -ENOMEM;
- }
+ if (!rxring->alloc)
+ goto err_set_null;
/*
* 16 Bytes align
@@ -762,9 +766,16 @@ jme_setup_rx_resources(struct jme_adapter *jme)
rxring->next_to_use = 0;
atomic_set(&rxring->next_to_clean, 0);
+ rxring->bufinf = kmalloc(sizeof(struct jme_buffer_info) *
+ jme->rx_ring_size, GFP_ATOMIC);
+ if (unlikely(!(rxring->bufinf)))
+ goto err_free_rxring;
+
/*
* Initiallize Receive Descriptors
*/
+ memset(rxring->bufinf, 0,
+ sizeof(struct jme_buffer_info) * jme->rx_ring_size);
for (i = 0 ; i < jme->rx_ring_size ; ++i) {
if (unlikely(jme_make_new_rx_buf(jme, i))) {
jme_free_rx_resources(jme);
@@ -775,6 +786,19 @@ jme_setup_rx_resources(struct jme_adapter *jme)
}
return 0;
+
+err_free_rxring:
+ dma_free_coherent(&(jme->pdev->dev),
+ RX_RING_ALLOC_SIZE(jme->rx_ring_size),
+ rxring->alloc,
+ rxring->dmaalloc);
+err_set_null:
+ rxring->desc = NULL;
+ rxring->dmaalloc = 0;
+ rxring->dma = 0;
+ rxring->bufinf = NULL;
+
+ return -ENOMEM;
}
static inline void
@@ -790,9 +814,9 @@ jme_enable_rx_engine(struct jme_adapter *jme)
/*
* Setup RX DMA Bass Address
*/
- jwrite32(jme, JME_RXDBA_LO, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+ jwrite32(jme, JME_RXDBA_LO, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
jwrite32(jme, JME_RXDBA_HI, (__u64)(jme->rxring[0].dma) >> 32);
- jwrite32(jme, JME_RXNDA, (__u64)jme->rxring[0].dma & 0xFFFFFFFFUL);
+ jwrite32(jme, JME_RXNDA, (__u64)(jme->rxring[0].dma) & 0xFFFFFFFFUL);
/*
* Setup RX Descriptor Count
@@ -856,27 +880,27 @@ jme_rxsum_ok(struct jme_adapter *jme, u16 flags)
if (!(flags & (RXWBFLAG_TCPON | RXWBFLAG_UDPON | RXWBFLAG_IPV4)))
return false;
- if (unlikely(!(flags & RXWBFLAG_MF) &&
- (flags & RXWBFLAG_TCPON) && !(flags & RXWBFLAG_TCPCS))) {
- msg_rx_err(jme, "TCP Checksum error.\n");
- goto out_sumerr;
+ if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_TCPON | RXWBFLAG_TCPCS))
+ == RXWBFLAG_TCPON)) {
+ if (flags & RXWBFLAG_IPV4)
+ msg_rx_err(jme, "TCP Checksum error\n");
+ return false;
}
- if (unlikely(!(flags & RXWBFLAG_MF) &&
- (flags & RXWBFLAG_UDPON) && !(flags & RXWBFLAG_UDPCS))) {
- msg_rx_err(jme, "UDP Checksum error.\n");
- goto out_sumerr;
+ if (unlikely((flags & (RXWBFLAG_MF | RXWBFLAG_UDPON | RXWBFLAG_UDPCS))
+ == RXWBFLAG_UDPON)) {
+ if (flags & RXWBFLAG_IPV4)
+ msg_rx_err(jme, "UDP Checksum error.\n");
+ return false;
}
- if (unlikely((flags & RXWBFLAG_IPV4) && !(flags & RXWBFLAG_IPCS))) {
+ if (unlikely((flags & (RXWBFLAG_IPV4 | RXWBFLAG_IPCS))
+ == RXWBFLAG_IPV4)) {
msg_rx_err(jme, "IPv4 Checksum error.\n");
- goto out_sumerr;
+ return false;
}
return true;
-
-out_sumerr:
- return false;
}
static void
@@ -1296,7 +1320,7 @@ jme_rx_empty_tasklet(unsigned long arg)
static void
jme_wake_queue_if_stopped(struct jme_adapter *jme)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
smp_wmb();
if (unlikely(netif_queue_stopped(jme->dev) &&
@@ -1483,12 +1507,7 @@ jme_msi(int irq, void *dev_id)
struct jme_adapter *jme = netdev_priv(netdev);
u32 intrstat;
- pci_dma_sync_single_for_cpu(jme->pdev,
- jme->shadow_dma,
- sizeof(u32) * SHADOW_REG_NR,
- PCI_DMA_FROMDEVICE);
- intrstat = jme->shadow_regs[SHADOW_IEVE];
- jme->shadow_regs[SHADOW_IEVE] = 0;
+ intrstat = jread32(jme, JME_IEVE);
jme_intr_msi(jme, intrstat);
@@ -1566,6 +1585,7 @@ jme_open(struct net_device *netdev)
jme_clear_pm(jme);
JME_NAPI_ENABLE(jme);
+ tasklet_enable(&jme->linkch_task);
tasklet_enable(&jme->txclean_task);
tasklet_hi_enable(&jme->rxclean_task);
tasklet_hi_enable(&jme->rxempty_task);
@@ -1574,7 +1594,6 @@ jme_open(struct net_device *netdev)
if (rc)
goto err_out;
- jme_enable_shadow(jme);
jme_start_irq(jme);
if (test_bit(JME_FLAG_SSET, &jme->flags))
@@ -1642,15 +1661,14 @@ jme_close(struct net_device *netdev)
netif_carrier_off(netdev);
jme_stop_irq(jme);
- jme_disable_shadow(jme);
jme_free_irq(jme);
JME_NAPI_DISABLE(jme);
- tasklet_kill(&jme->linkch_task);
- tasklet_kill(&jme->txclean_task);
- tasklet_kill(&jme->rxclean_task);
- tasklet_kill(&jme->rxempty_task);
+ tasklet_disable(&jme->linkch_task);
+ tasklet_disable(&jme->txclean_task);
+ tasklet_disable(&jme->rxclean_task);
+ tasklet_disable(&jme->rxempty_task);
jme_reset_ghc_speed(jme);
jme_disable_rx_engine(jme);
@@ -1668,7 +1686,7 @@ static int
jme_alloc_txdesc(struct jme_adapter *jme,
struct sk_buff *skb)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
int idx, nr_alloc, mask = jme->tx_ring_mask;
idx = txring->next_to_use;
@@ -1722,7 +1740,7 @@ jme_fill_tx_map(struct pci_dev *pdev,
static void
jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct txdesc *txdesc = txring->desc, *ctxdesc;
struct jme_buffer_info *txbi = txring->bufinf, *ctxbi;
u8 hidma = jme->dev->features & NETIF_F_HIGHDMA;
@@ -1835,7 +1853,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags)
static int
jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct txdesc *txdesc;
struct jme_buffer_info *txbi;
u8 flags;
@@ -1883,7 +1901,7 @@ jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
static void
jme_stop_queue_if_full(struct jme_adapter *jme)
{
- struct jme_ring *txring = jme->txring;
+ struct jme_ring *txring = &(jme->txring[0]);
struct jme_buffer_info *txbi = txring->bufinf;
int idx = atomic_read(&txring->next_to_clean);
@@ -2725,14 +2743,6 @@ jme_init_one(struct pci_dev *pdev,
rc = -ENOMEM;
goto err_out_free_netdev;
}
- jme->shadow_regs = pci_alloc_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- &(jme->shadow_dma));
- if (!(jme->shadow_regs)) {
- jeprintk(pdev, "Allocating shadow register mapping error.\n");
- rc = -ENOMEM;
- goto err_out_unmap;
- }
if (no_pseudohp) {
apmc = jread32(jme, JME_APMC) & ~JME_APMC_PSEUDO_HP_EN;
@@ -2768,6 +2778,7 @@ jme_init_one(struct pci_dev *pdev,
tasklet_init(&jme->rxempty_task,
&jme_rx_empty_tasklet,
(unsigned long) jme);
+ tasklet_disable_nosync(&jme->linkch_task);
tasklet_disable_nosync(&jme->txclean_task);
tasklet_disable_nosync(&jme->rxclean_task);
tasklet_disable_nosync(&jme->rxempty_task);
@@ -2817,7 +2828,7 @@ jme_init_one(struct pci_dev *pdev,
if (!jme->mii_if.phy_id) {
rc = -EIO;
jeprintk(pdev, "Can not find phy_id.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
jme->reg_ghc |= GHC_LINK_POLL;
@@ -2846,7 +2857,7 @@ jme_init_one(struct pci_dev *pdev,
if (rc) {
jeprintk(pdev,
"Reload eeprom for reading MAC Address error.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
jme_load_macaddr(netdev);
@@ -2862,7 +2873,7 @@ jme_init_one(struct pci_dev *pdev,
rc = register_netdev(netdev);
if (rc) {
jeprintk(pdev, "Cannot register net device.\n");
- goto err_out_free_shadow;
+ goto err_out_unmap;
}
msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n",
@@ -2876,11 +2887,6 @@ jme_init_one(struct pci_dev *pdev,
return 0;
-err_out_free_shadow:
- pci_free_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- jme->shadow_regs,
- jme->shadow_dma);
err_out_unmap:
iounmap(jme->regs);
err_out_free_netdev:
@@ -2901,10 +2907,6 @@ jme_remove_one(struct pci_dev *pdev)
struct jme_adapter *jme = netdev_priv(netdev);
unregister_netdev(netdev);
- pci_free_consistent(pdev,
- sizeof(u32) * SHADOW_REG_NR,
- jme->shadow_regs,
- jme->shadow_dma);
iounmap(jme->regs);
pci_set_drvdata(pdev, NULL);
free_netdev(netdev);
@@ -2930,8 +2932,6 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state)
tasklet_disable(&jme->rxclean_task);
tasklet_disable(&jme->rxempty_task);
- jme_disable_shadow(jme);
-
if (netif_carrier_ok(netdev)) {
if (test_bit(JME_FLAG_POLL, &jme->flags))
jme_polling_mode(jme);
@@ -2983,7 +2983,6 @@ jme_resume(struct pci_dev *pdev)
else
jme_reset_phy_processor(jme);
- jme_enable_shadow(jme);
jme_start_irq(jme);
netif_device_attach(netdev);
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 0996a069ac7..251abed3817 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -25,7 +25,7 @@
#define __JME_H_INCLUDED__
#define DRV_NAME "jme"
-#define DRV_VERSION "1.0.4"
+#define DRV_VERSION "1.0.5"
#define PFX DRV_NAME ": "
#define PCI_DEVICE_ID_JMICRON_JMC250 0x0250
@@ -247,7 +247,7 @@ enum jme_txdesc_flags_bits {
};
#define TXDESC_MSS_SHIFT 2
-enum jme_rxdescwb_flags_bits {
+enum jme_txwbdesc_flags_bits {
TXWBFLAG_OWN = 0x80,
TXWBFLAG_INT = 0x40,
TXWBFLAG_TMOUT = 0x20,
@@ -372,7 +372,6 @@ struct jme_buffer_info {
/*
* The structure holding buffer information and ring descriptors all together.
*/
-#define MAX_RING_DESC_NR 1024
struct jme_ring {
void *alloc; /* pointer to allocated memory */
void *desc; /* pointer to ring memory */
@@ -380,7 +379,7 @@ struct jme_ring {
dma_addr_t dma; /* phys address for ring dma */
/* Buffer information corresponding to each descriptor */
- struct jme_buffer_info bufinf[MAX_RING_DESC_NR];
+ struct jme_buffer_info *bufinf;
int next_to_use;
atomic_t next_to_clean;
@@ -411,13 +410,10 @@ struct jme_ring {
/*
* Jmac Adapter Private data
*/
-#define SHADOW_REG_NR 8
struct jme_adapter {
struct pci_dev *pdev;
struct net_device *dev;
void __iomem *regs;
- dma_addr_t shadow_dma;
- u32 *shadow_regs;
struct mii_if_info mii_if;
struct jme_ring rxring[RX_RING_NR];
struct jme_ring txring[TX_RING_NR];
@@ -464,10 +460,6 @@ struct jme_adapter {
DECLARE_NET_DEVICE_STATS
};
-enum shadow_reg_val {
- SHADOW_IEVE = 0,
-};
-
enum jme_flags_bits {
JME_FLAG_MSI = 1,
JME_FLAG_SSET = 2,
@@ -1104,13 +1096,6 @@ enum jme_chipmode_shifts {
};
/*
- * Shadow base address register bits
- */
-enum jme_shadow_base_address_bits {
- SHBA_POSTEN = 0x1,
-};
-
-/*
* Aggressive Power Mode Control
*/
enum jme_apmc_bits {
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 633808d447b..30fd4f5f1d5 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -1016,7 +1016,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
out:
spin_unlock_irqrestore(&lp->devlock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index 070fa450087..51e11c3e53e 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -983,7 +983,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -1028,7 +1028,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void print_eth(unsigned char *add, char *str)
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index f28c2334300..d6be36000c5 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -414,7 +414,7 @@ static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
dev->stats.tx_bytes += send_length;
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c
index 96e7248876c..da8d0a0ca94 100644
--- a/drivers/net/ll_temac_main.c
+++ b/drivers/net/ll_temac_main.c
@@ -591,7 +591,7 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
/* Kick off the transfer */
temac_dma_out32(lp, TX_TAILDESC_PTR, tail_p); /* DMA start */
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index da472c68748..51bbce72bed 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -89,7 +89,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
} else
lb_stats->drops++;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *loopback_get_stats(struct net_device *dev)
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index d44bddbee37..c292bad411e 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -871,7 +871,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -906,7 +906,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
dev->stats.tx_packets++;
}
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index dab45339d3a..149e0ed4a05 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -411,7 +411,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The typical workload of the driver:
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 5b5c25368d1..d22952c78f1 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -678,7 +678,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void macb_free_consistent(struct macb *bp)
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 1427755c224..7d7577b598e 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -581,7 +581,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
spin_unlock_irqrestore(&mp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void mace_set_multicast(struct net_device *dev)
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 5d04d94f2a2..92ceb689b4d 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -715,7 +715,7 @@ static int meth_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->meth_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -784,7 +784,7 @@ static const struct net_device_ops meth_netdev_ops = {
/*
* The init function.
*/
-static int __init meth_probe(struct platform_device *pdev)
+static int __devinit meth_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct meth_private *priv;
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index b3b9a147d09..8ea98bd89ff 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -141,7 +141,7 @@ static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
mipsnet_put_todevice(dev, skb);
- return 0;
+ return NETDEV_TX_OK;
}
static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t len)
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c
index 08c43f2ae72..d5c18c67425 100644
--- a/drivers/net/mlx4/en_tx.c
+++ b/drivers/net/mlx4/en_tx.c
@@ -764,7 +764,7 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
/* Poll CQ here */
mlx4_en_xmit_poll(priv, tx_ind);
- return 0;
+ return NETDEV_TX_OK;
tx_drop:
dev_kfree_skb_any(skb);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 1f6e36ea669..1a34f7e11d9 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -2748,7 +2748,7 @@ again:
/* The packet is gone, so we must
* return 0 */
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
/* adjust the len to account for the zero pad
* so that the nic can know how long it is */
@@ -2892,7 +2892,7 @@ again:
tx->stop_queue++;
netif_tx_stop_queue(netdev_queue);
}
- return 0;
+ return NETDEV_TX_OK;
abort_linearize:
/* Free any DMA resources we've alloced and clear out the skb
@@ -2936,7 +2936,7 @@ abort_linearize:
drop:
dev_kfree_skb_any(skb);
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
@@ -2968,13 +2968,13 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev)
}
}
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
drop:
ss = &mgp->ss[skb_get_queue_mapping(skb)];
dev_kfree_skb_any(skb);
ss->stats.tx_dropped += 1;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 5f0758bda6b..29ebebc6a95 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -692,7 +692,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
DTX(("tbusy=0, returning 0\n"));
netif_start_queue(dev);
spin_unlock_irqrestore(&mp->irq_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* Create the MyriNet MAC header for an arbitrary protocol layer
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index c9bfe4eea18..481aa2d287a 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -2125,7 +2125,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void netdev_tx_done(struct net_device *dev)
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 946366dcc99..9f4235466d5 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -134,7 +134,7 @@ netx_eth_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irq(&priv->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void netx_eth_receive(struct net_device *ndev)
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index f86e05047d1..e22d0861589 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -57,8 +57,8 @@
#define _NETXEN_NIC_LINUX_MAJOR 4
#define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 30
-#define NETXEN_NIC_LINUX_VERSIONID "4.0.30"
+#define _NETXEN_NIC_LINUX_SUBVERSION 41
+#define NETXEN_NIC_LINUX_VERSIONID "4.0.41"
#define NETXEN_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define _major(v) (((v) >> 24) & 0xff)
@@ -143,18 +143,13 @@
#define NX_ETHERMTU 1500
#define NX_MAX_ETHERHDR 32 /* This contains some padding */
-#define NX_RX_NORMAL_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU)
+#define NX_P2_RX_BUF_MAX_LEN 1760
+#define NX_P3_RX_BUF_MAX_LEN (NX_MAX_ETHERHDR + NX_ETHERMTU)
#define NX_P2_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P2_MAX_MTU)
#define NX_P3_RX_JUMBO_BUF_MAX_LEN (NX_MAX_ETHERHDR + P3_MAX_MTU)
#define NX_CT_DEFAULT_RX_BUF_LEN 2048
-#define MAX_RX_BUFFER_LENGTH 1760
-#define MAX_RX_JUMBO_BUFFER_LENGTH 8062
-#define MAX_RX_LRO_BUFFER_LENGTH (8062)
-#define RX_DMA_MAP_LEN (MAX_RX_BUFFER_LENGTH - 2)
-#define RX_JUMBO_DMA_MAP_LEN \
- (MAX_RX_JUMBO_BUFFER_LENGTH - 2)
-#define RX_LRO_DMA_MAP_LEN (MAX_RX_LRO_BUFFER_LENGTH - 2)
+#define NX_RX_LRO_BUFFER_LENGTH (8060)
/*
* Maximum number of ring contexts
@@ -200,13 +195,20 @@
#define RCV_RING_JUMBO 1
#define RCV_RING_LRO 2
-#define MAX_CMD_DESCRIPTORS 4096
-#define MAX_RCV_DESCRIPTORS 16384
-#define MAX_CMD_DESCRIPTORS_HOST 1024
-#define MAX_RCV_DESCRIPTORS_1G 2048
-#define MAX_RCV_DESCRIPTORS_10G 4096
-#define MAX_JUMBO_RCV_DESCRIPTORS 1024
+#define MIN_CMD_DESCRIPTORS 64
+#define MIN_RCV_DESCRIPTORS 64
+#define MIN_JUMBO_DESCRIPTORS 32
+
+#define MAX_CMD_DESCRIPTORS 1024
+#define MAX_RCV_DESCRIPTORS_1G 4096
+#define MAX_RCV_DESCRIPTORS_10G 8192
+#define MAX_JUMBO_RCV_DESCRIPTORS_1G 512
+#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024
#define MAX_LRO_RCV_DESCRIPTORS 8
+
+#define DEFAULT_RCV_DESCRIPTORS_1G 2048
+#define DEFAULT_RCV_DESCRIPTORS_10G 4096
+
#define NETXEN_CTX_SIGNATURE 0xdee0
#define NETXEN_CTX_SIGNATURE_V2 0x0002dee0
#define NETXEN_CTX_RESET 0xbad0
@@ -302,6 +304,10 @@ struct netxen_ring_ctx {
#define FLAGS_IPSEC_SA_ADD 0x04
#define FLAGS_IPSEC_SA_DELETE 0x08
#define FLAGS_VLAN_TAGGED 0x10
+#define FLAGS_VLAN_OOB 0x40
+
+#define netxen_set_tx_vlan_tci(cmd_desc, v) \
+ (cmd_desc)->vlan_TCI = cpu_to_le16(v);
#define netxen_set_cmd_desc_port(cmd_desc, var) \
((cmd_desc)->port_ctxid |= ((var) & 0x0F))
@@ -316,58 +322,33 @@ struct netxen_ring_ctx {
cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))
#define netxen_set_tx_frags_len(_desc, _frags, _len) \
- (_desc)->num_of_buffers_total_length = \
+ (_desc)->nfrags__length = \
cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))
struct cmd_desc_type0 {
u8 tcp_hdr_offset; /* For LSO only */
u8 ip_hdr_offset; /* For LSO only */
- /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */
- __le16 flags_opcode;
- /* Bit pattern: 0-7 total number of segments,
- 8-31 Total size of the packet */
- __le32 num_of_buffers_total_length;
- union {
- struct {
- __le32 addr_low_part2;
- __le32 addr_high_part2;
- };
- __le64 addr_buffer2;
- };
+ __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */
+ __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */
+
+ __le64 addr_buffer2;
- __le16 reference_handle; /* changed to u16 to add mss */
- __le16 mss; /* passed by NDIS_PACKET for LSO */
- /* Bit pattern 0-3 port, 0-3 ctx id */
- u8 port_ctxid;
+ __le16 reference_handle;
+ __le16 mss;
+ u8 port_ctxid; /* 7:4 ctxid 3:0 port */
u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */
__le16 conn_id; /* IPSec offoad only */
- union {
- struct {
- __le32 addr_low_part3;
- __le32 addr_high_part3;
- };
- __le64 addr_buffer3;
- };
- union {
- struct {
- __le32 addr_low_part1;
- __le32 addr_high_part1;
- };
- __le64 addr_buffer1;
- };
+ __le64 addr_buffer3;
+ __le64 addr_buffer1;
__le16 buffer_length[4];
- union {
- struct {
- __le32 addr_low_part4;
- __le32 addr_high_part4;
- };
- __le64 addr_buffer4;
- };
+ __le64 addr_buffer4;
- __le64 unused;
+ __le16 vlan_TCI;
+ __le16 reserved;
+ __le32 reserved2;
} __attribute__ ((aligned(64)));
@@ -380,6 +361,7 @@ struct rcv_desc {
};
/* opcode field in status_desc */
+#define NETXEN_NIC_SYN_OFFLOAD 0x03
#define NETXEN_NIC_RXPKT_DESC 0x04
#define NETXEN_OLD_RXPKT_DESC 0x3f
#define NETXEN_NIC_RESPONSE_DESC 0x05
@@ -1078,6 +1060,9 @@ typedef struct {
#define NX_MAC_EVENT 0x1
+#define NX_IP_UP 2
+#define NX_IP_DOWN 3
+
/*
* Driver --> Firmware
*/
@@ -1132,6 +1117,9 @@ typedef struct {
#define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5)
#define NX_FW_CAPABILITY_SWITCHING (1 << 6)
+#define NX_FW_CAPABILITY_PEXQ (1 << 7)
+#define NX_FW_CAPABILITY_BDG (1 << 8)
+#define NX_FW_CAPABILITY_FVLANTX (1 << 9)
/* module types */
#define LINKEVENT_MODULE_NOT_PRESENT 1
@@ -1315,29 +1303,11 @@ struct netxen_adapter {
nx_nic_intr_coalesce_t coal;
- u32 fw_major;
+ u32 resv5;
u32 fw_version;
const struct firmware *fw;
};
-/*
- * NetXen dma watchdog control structure
- *
- * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive
- * Bit 1 : disable_request => 1 req disable dma watchdog
- * Bit 2 : enable_request => 1 req enable dma watchdog
- * Bit 3-31 : unused
- */
-
-#define netxen_set_dma_watchdog_disable_req(config_word) \
- _netxen_set_bits(config_word, 1, 1, 1)
-#define netxen_set_dma_watchdog_enable_req(config_word) \
- _netxen_set_bits(config_word, 2, 1, 1)
-#define netxen_get_dma_watchdog_enabled(config_word) \
- ((config_word) & 0x1)
-#define netxen_get_dma_watchdog_disabled(config_word) \
- (((config_word) >> 1) & 0x1)
-
int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
@@ -1398,8 +1368,9 @@ unsigned long netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter,
unsigned long long addr);
/* Functions from netxen_nic_init.c */
-void netxen_free_adapter_offload(struct netxen_adapter *adapter);
-int netxen_initialize_adapter_offload(struct netxen_adapter *adapter);
+int netxen_init_dummy_dma(struct netxen_adapter *adapter);
+void netxen_free_dummy_dma(struct netxen_adapter *adapter);
+
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
int netxen_load_firmware(struct netxen_adapter *adapter);
int netxen_need_fw_reset(struct netxen_adapter *adapter);
@@ -1443,6 +1414,7 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
int netxen_config_rss(struct netxen_adapter *adapter, int enable);
+int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd);
int netxen_linkevent_request(struct netxen_adapter *adapter, int enable);
void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup);
@@ -1455,6 +1427,9 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev);
void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
struct nx_host_tx_ring *tx_ring);
+/* Functions from netxen_nic_main.c */
+int netxen_nic_reset_context(struct netxen_adapter *);
+
/*
* NetXen Board information
*/
@@ -1505,56 +1480,6 @@ static inline void get_brd_name_by_type(u32 type, char *name)
name = "Unknown";
}
-static inline int
-dma_watchdog_shutdown_request(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- /* check if already inactive */
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- if (netxen_get_dma_watchdog_enabled(ctrl) == 0)
- return 1;
-
- /* Send the disable request */
- netxen_set_dma_watchdog_disable_req(ctrl);
- NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl);
-
- return 0;
-}
-
-static inline int
-dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- return (netxen_get_dma_watchdog_enabled(ctrl) == 0);
-}
-
-static inline int
-dma_watchdog_wakeup(struct netxen_adapter *adapter)
-{
- u32 ctrl;
-
- ctrl = adapter->hw_read_wx(adapter,
- NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
-
- if (netxen_get_dma_watchdog_enabled(ctrl))
- return 1;
-
- /* send the wakeup request */
- netxen_set_dma_watchdog_enable_req(ctrl);
-
- NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl);
-
- return 0;
-}
-
-
static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring)
{
smp_mb();
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c
index 9f8ae4719e2..9e0469643d3 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/netxen/netxen_nic_ctx.c
@@ -647,7 +647,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
}
rds_ring->desc_head = (struct rcv_desc *)addr;
- if (adapter->fw_major < 4)
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
rds_ring->crb_rcv_producer =
recv_crb_registers[port].crb_rcv_producer[ring];
}
@@ -675,7 +675,7 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
}
- if (adapter->fw_major >= 4) {
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
err = nx_fw_cmd_create_rx_ctx(adapter);
if (err)
goto err_out_free;
@@ -705,7 +705,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
int port = adapter->portnum;
- if (adapter->fw_major >= 4) {
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
nx_fw_cmd_destroy_rx_ctx(adapter);
nx_fw_cmd_destroy_tx_ctx(adapter);
} else {
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index e16ea46c24b..39a308c363c 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -490,28 +490,86 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
}
static void
-netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
+netxen_nic_get_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
{
struct netxen_adapter *adapter = netdev_priv(dev);
- ring->rx_pending = 0;
- ring->rx_jumbo_pending = 0;
- ring->rx_pending += adapter->recv_ctx.
- rds_rings[RCV_RING_NORMAL].num_desc;
- ring->rx_jumbo_pending += adapter->recv_ctx.
- rds_rings[RCV_RING_JUMBO].num_desc;
+ ring->rx_pending = adapter->num_rxd;
+ ring->rx_jumbo_pending = adapter->num_jumbo_rxd;
+ ring->rx_jumbo_pending += adapter->num_lro_rxd;
ring->tx_pending = adapter->num_txd;
- if (adapter->ahw.port_type == NETXEN_NIC_GBE)
+ if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
- else
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ } else {
ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
- ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST;
- ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS;
+ ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ }
+
+ ring->tx_max_pending = MAX_CMD_DESCRIPTORS;
+
ring->rx_mini_max_pending = 0;
ring->rx_mini_pending = 0;
}
+static u32
+netxen_validate_ringparam(u32 val, u32 min, u32 max, char *r_name)
+{
+ u32 num_desc;
+ num_desc = max(val, min);
+ num_desc = min(num_desc, max);
+ num_desc = roundup_pow_of_two(num_desc);
+
+ if (val != num_desc) {
+ printk(KERN_INFO "%s: setting %s ring size %d instead of %d\n",
+ netxen_nic_driver_name, r_name, num_desc, val);
+ }
+
+ return num_desc;
+}
+
+static int
+netxen_nic_set_ringparam(struct net_device *dev,
+ struct ethtool_ringparam *ring)
+{
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ u16 max_rcv_desc = MAX_RCV_DESCRIPTORS_10G;
+ u16 max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ u16 num_rxd, num_jumbo_rxd, num_txd;
+
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return -EOPNOTSUPP;
+
+ if (ring->rx_mini_pending)
+ return -EOPNOTSUPP;
+
+ if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
+ max_rcv_desc = MAX_RCV_DESCRIPTORS_1G;
+ max_jumbo_desc = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ }
+
+ num_rxd = netxen_validate_ringparam(ring->rx_pending,
+ MIN_RCV_DESCRIPTORS, max_rcv_desc, "rx");
+
+ num_jumbo_rxd = netxen_validate_ringparam(ring->rx_jumbo_pending,
+ MIN_JUMBO_DESCRIPTORS, max_jumbo_desc, "rx jumbo");
+
+ num_txd = netxen_validate_ringparam(ring->tx_pending,
+ MIN_CMD_DESCRIPTORS, MAX_CMD_DESCRIPTORS, "tx");
+
+ if (num_rxd == adapter->num_rxd && num_txd == adapter->num_txd &&
+ num_jumbo_rxd == adapter->num_jumbo_rxd)
+ return 0;
+
+ adapter->num_rxd = num_rxd;
+ adapter->num_jumbo_rxd = num_jumbo_rxd;
+ adapter->num_txd = num_txd;
+
+ return netxen_nic_reset_context(adapter);
+}
+
static void
netxen_nic_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
@@ -893,6 +951,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
.get_eeprom_len = netxen_nic_get_eeprom_len,
.get_eeprom = netxen_nic_get_eeprom,
.get_ringparam = netxen_nic_get_ringparam,
+ .set_ringparam = netxen_nic_set_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
.set_tx_csum = ethtool_op_set_tx_csum,
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index 82410367564..a7328584a21 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -852,7 +852,7 @@ enum {
#define NX_PEG_TUNE_MN_PRESENT 0x1
#define NX_PEG_TUNE_CAPABILITY (NETXEN_CAM_RAM(0x02c))
-#define NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL (0x14)
+#define NETXEN_DMA_WATCHDOG_CTRL (NETXEN_CAM_RAM(0x14))
#define NETXEN_PEG_ALIVE_COUNTER (NETXEN_CAM_RAM(0xb0))
#define ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index b9123d445c9..ddb9deb12b3 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -706,6 +706,30 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable)
return rv;
}
+int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd)
+{
+ nx_nic_req_t req;
+ u64 word;
+ int rv;
+
+ memset(&req, 0, sizeof(nx_nic_req_t));
+ req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
+
+ word = NX_NIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16);
+ req.req_hdr = cpu_to_le64(word);
+
+ req.words[0] = cpu_to_le64(cmd);
+ req.words[1] = cpu_to_le64(ip);
+
+ rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+ if (rv != 0) {
+ printk(KERN_ERR "%s: could not notify %s IP 0x%x reuqest\n",
+ adapter->netdev->name,
+ (cmd == NX_IP_UP) ? "Add" : "Remove", ip);
+ }
+ return rv;
+}
+
int netxen_linkevent_request(struct netxen_adapter *adapter, int enable)
{
nx_nic_req_t req;
@@ -2021,7 +2045,6 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter)
fw_minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
fw_build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
- adapter->fw_major = fw_major;
adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build);
if (adapter->portnum == 0) {
@@ -2047,6 +2070,9 @@ void netxen_nic_get_firmware_info(struct netxen_adapter *adapter)
dev_info(&pdev->dev, "firmware running in %s mode\n",
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);
}
int
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 7acf204e38c..81253abbfa3 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -254,9 +254,14 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
rds_ring->skb_size =
NX_CT_DEFAULT_RX_BUF_LEN;
} else {
- rds_ring->dma_size = RX_DMA_MAP_LEN;
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ rds_ring->dma_size =
+ NX_P3_RX_BUF_MAX_LEN;
+ else
+ rds_ring->dma_size =
+ NX_P2_RX_BUF_MAX_LEN;
rds_ring->skb_size =
- MAX_RX_BUFFER_LENGTH;
+ rds_ring->dma_size + NET_IP_ALIGN;
}
break;
@@ -274,8 +279,8 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
case RCV_RING_LRO:
rds_ring->num_desc = adapter->num_lro_rxd;
- rds_ring->dma_size = RX_LRO_DMA_MAP_LEN;
- rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH;
+ rds_ring->dma_size = NX_RX_LRO_BUFFER_LENGTH;
+ rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN;
break;
}
@@ -887,22 +892,10 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
return 0;
}
-void netxen_request_firmware(struct netxen_adapter *adapter)
+static int
+netxen_p3_has_mn(struct netxen_adapter *adapter)
{
u32 capability, flashed_ver;
- u8 fw_type;
- struct pci_dev *pdev = adapter->pdev;
- int rc = 0;
-
- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
- fw_type = NX_P2_MN_ROMIMAGE;
- goto request_fw;
- } else {
- fw_type = NX_P3_CT_ROMIMAGE;
- goto request_fw;
- }
-
-request_mn:
capability = 0;
netxen_rom_fast_read(adapter,
@@ -910,23 +903,35 @@ request_mn:
flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
+
capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
- if (capability & NX_PEG_TUNE_MN_PRESENT) {
- fw_type = NX_P3_MN_ROMIMAGE;
- goto request_fw;
- }
+ if (capability & NX_PEG_TUNE_MN_PRESENT)
+ return 1;
}
+ return 0;
+}
- fw_type = NX_FLASH_ROMIMAGE;
- adapter->fw = NULL;
- goto done;
+void netxen_request_firmware(struct netxen_adapter *adapter)
+{
+ u8 fw_type;
+ struct pci_dev *pdev = adapter->pdev;
+ int rc = 0;
+
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+ fw_type = NX_P2_MN_ROMIMAGE;
+ goto request_fw;
+ }
+
+ fw_type = netxen_p3_has_mn(adapter) ?
+ NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE;
request_fw:
rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
if (rc != 0) {
- if (fw_type == NX_P3_CT_ROMIMAGE) {
+ if (fw_type == NX_P3_MN_ROMIMAGE) {
msleep(1);
- goto request_mn;
+ fw_type = NX_P3_CT_ROMIMAGE;
+ goto request_fw;
}
fw_type = NX_FLASH_ROMIMAGE;
@@ -938,9 +943,10 @@ request_fw:
if (rc != 0) {
release_firmware(adapter->fw);
- if (fw_type == NX_P3_CT_ROMIMAGE) {
+ if (fw_type == NX_P3_MN_ROMIMAGE) {
msleep(1);
- goto request_mn;
+ fw_type = NX_P3_CT_ROMIMAGE;
+ goto request_fw;
}
fw_type = NX_FLASH_ROMIMAGE;
@@ -960,19 +966,20 @@ netxen_release_firmware(struct netxen_adapter *adapter)
release_firmware(adapter->fw);
}
-int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
+int netxen_init_dummy_dma(struct netxen_adapter *adapter)
{
- uint64_t addr;
- uint32_t hi;
- uint32_t lo;
+ u64 addr;
+ u32 hi, lo;
+
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return 0;
- adapter->dummy_dma.addr =
- pci_alloc_consistent(adapter->pdev,
+ adapter->dummy_dma.addr = pci_alloc_consistent(adapter->pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
&adapter->dummy_dma.phys_addr);
if (adapter->dummy_dma.addr == NULL) {
- printk("%s: ERROR: Could not allocate dummy DMA memory\n",
- __func__);
+ dev_err(&adapter->pdev->dev,
+ "ERROR: Could not allocate dummy DMA memory\n");
return -ENOMEM;
}
@@ -983,29 +990,41 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi);
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo);
- if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
- uint32_t temp = 0;
- NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp);
- }
-
return 0;
}
-void netxen_free_adapter_offload(struct netxen_adapter *adapter)
+/*
+ * NetXen DMA watchdog control:
+ *
+ * Bit 0 : enabled => R/O: 1 watchdog active, 0 inactive
+ * Bit 1 : disable_request => 1 req disable dma watchdog
+ * Bit 2 : enable_request => 1 req enable dma watchdog
+ * Bit 3-31 : unused
+ */
+void netxen_free_dummy_dma(struct netxen_adapter *adapter)
{
int i = 100;
+ u32 ctrl;
+
+ if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return;
if (!adapter->dummy_dma.addr)
return;
- if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
- do {
- if (dma_watchdog_shutdown_request(adapter) == 1)
- break;
+ ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
+ if ((ctrl & 0x1) != 0) {
+ NXWR32(adapter, NETXEN_DMA_WATCHDOG_CTRL, (ctrl | 0x2));
+
+ while ((ctrl & 0x1) != 0) {
+
msleep(50);
- if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+
+ ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
+
+ if (--i == 0)
break;
- } while (--i);
+ };
}
if (i) {
@@ -1014,10 +1033,8 @@ void netxen_free_adapter_offload(struct netxen_adapter *adapter)
adapter->dummy_dma.addr,
adapter->dummy_dma.phys_addr);
adapter->dummy_dma.addr = NULL;
- } else {
- printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
- adapter->netdev->name);
- }
+ } else
+ dev_err(&adapter->pdev->dev, "dma_watchdog_shutdown failed\n");
}
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
@@ -1090,10 +1107,6 @@ int netxen_init_firmware(struct netxen_adapter *adapter)
NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);
NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
- if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) {
- adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
- }
-
return err;
}
@@ -1303,6 +1316,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
switch (opcode) {
case NETXEN_NIC_RXPKT_DESC:
case NETXEN_OLD_RXPKT_DESC:
+ case NETXEN_NIC_SYN_OFFLOAD:
break;
case NETXEN_NIC_RESPONSE_DESC:
netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
@@ -1475,7 +1489,7 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
NXWR32(adapter, rds_ring->crb_rcv_producer,
(producer-1) & (rds_ring->num_desc-1));
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
/*
* Write a doorbell msg to tell phanmon of change in
* receive ring producer
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 637ac8b89ba..40549a0e9ff 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -39,6 +39,7 @@
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <linux/ipv6.h>
+#include <linux/inetdevice.h>
MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
MODULE_LICENSE("GPL");
@@ -65,7 +66,7 @@ static int netxen_nic_open(struct net_device *netdev);
static int netxen_nic_close(struct net_device *netdev);
static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *);
static void netxen_tx_timeout(struct net_device *netdev);
-static void netxen_tx_timeout_task(struct work_struct *work);
+static void netxen_reset_task(struct work_struct *work);
static void netxen_watchdog(unsigned long);
static int netxen_nic_poll(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -181,7 +182,7 @@ netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev)
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
- return 1;
+ return -ENOMEM;
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
@@ -282,12 +283,16 @@ nx_update_dma_mask(struct netxen_adapter *adapter)
return 0;
}
-static void netxen_check_options(struct netxen_adapter *adapter)
+static void
+netxen_check_options(struct netxen_adapter *adapter)
{
- if (adapter->ahw.port_type == NETXEN_NIC_XGBE)
- adapter->num_rxd = MAX_RCV_DESCRIPTORS_10G;
- else if (adapter->ahw.port_type == NETXEN_NIC_GBE)
- adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G;
+ if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
+ } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
+ adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
+ adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
+ }
adapter->msix_supported = 0;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
@@ -305,11 +310,15 @@ static void netxen_check_options(struct netxen_adapter *adapter)
}
}
- adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST;
- adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS;
- adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
+ adapter->num_txd = MAX_CMD_DESCRIPTORS;
- return;
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+ adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
+ adapter->max_rds_rings = 3;
+ } else {
+ adapter->num_lro_rxd = 0;
+ adapter->max_rds_rings = 2;
+ }
}
static int
@@ -744,7 +753,7 @@ netxen_start_firmware(struct netxen_adapter *adapter, int request_fw)
}
- err = netxen_initialize_adapter_offload(adapter);
+ err = netxen_init_dummy_dma(adapter);
if (err)
return err;
@@ -760,10 +769,14 @@ wait_init:
/* Handshake with the card before we register the devices. */
err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
if (err) {
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
return err;
}
+ nx_update_dma_mask(adapter);
+
+ netxen_nic_get_firmware_info(adapter);
+
return 0;
}
@@ -814,6 +827,20 @@ netxen_nic_free_irq(struct netxen_adapter *adapter)
}
}
+static void
+netxen_nic_init_coalesce_defaults(struct netxen_adapter *adapter)
+{
+ adapter->coal.flags = NETXEN_NIC_INTR_DEFAULT;
+ adapter->coal.normal.data.rx_time_us =
+ NETXEN_DEFAULT_INTR_COALESCE_RX_TIME_US;
+ adapter->coal.normal.data.rx_packets =
+ NETXEN_DEFAULT_INTR_COALESCE_RX_PACKETS;
+ adapter->coal.normal.data.tx_time_us =
+ NETXEN_DEFAULT_INTR_COALESCE_TX_TIME_US;
+ adapter->coal.normal.data.tx_packets =
+ NETXEN_DEFAULT_INTR_COALESCE_TX_PACKETS;
+}
+
static int
netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
{
@@ -836,6 +863,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
if (adapter->max_sds_rings > 1)
netxen_config_rss(adapter, 1);
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netxen_config_intr_coalesce(adapter);
+
netxen_napi_enable(adapter);
if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION)
@@ -880,17 +910,15 @@ netxen_nic_attach(struct netxen_adapter *adapter)
struct nx_host_rds_ring *rds_ring;
struct nx_host_tx_ring *tx_ring;
+ if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+ return 0;
+
err = netxen_init_firmware(adapter);
if (err != 0) {
printk(KERN_ERR "Failed to init firmware\n");
return -EIO;
}
- if (adapter->fw_major < 4)
- adapter->max_rds_rings = 3;
- else
- adapter->max_rds_rings = 2;
-
err = netxen_alloc_sw_resources(adapter);
if (err) {
printk(KERN_ERR "%s: Error in setting sw resources\n",
@@ -907,7 +935,7 @@ netxen_nic_attach(struct netxen_adapter *adapter)
goto err_out_free_sw;
}
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
tx_ring = adapter->tx_ring;
tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum];
tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum];
@@ -931,6 +959,9 @@ netxen_nic_attach(struct netxen_adapter *adapter)
goto err_out_free_rxbuf;
}
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netxen_nic_init_coalesce_defaults(adapter);
+
adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
return 0;
@@ -945,6 +976,9 @@ err_out_free_sw:
static void
netxen_nic_detach(struct netxen_adapter *adapter)
{
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ return;
+
netxen_free_hw_resources(adapter);
netxen_release_rx_buffers(adapter);
netxen_nic_free_irq(adapter);
@@ -953,6 +987,95 @@ netxen_nic_detach(struct netxen_adapter *adapter)
adapter->is_up = 0;
}
+int
+netxen_nic_reset_context(struct netxen_adapter *adapter)
+{
+ int err = 0;
+ struct net_device *netdev = adapter->netdev;
+
+ if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
+
+ if (netif_running(netdev))
+ netxen_nic_down(adapter, netdev);
+
+ netxen_nic_detach(adapter);
+
+ err = netxen_nic_attach(adapter);
+ if (err)
+ goto done;
+
+ if (netif_running(netdev))
+ err = netxen_nic_up(adapter, netdev);
+ }
+done:
+ return err;
+}
+
+static int
+netxen_setup_netdev(struct netxen_adapter *adapter,
+ struct net_device *netdev)
+{
+ int err = 0;
+ struct pci_dev *pdev = adapter->pdev;
+
+ adapter->rx_csum = 1;
+ adapter->mc_enabled = 0;
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ adapter->max_mc_count = 38;
+ else
+ adapter->max_mc_count = 16;
+
+ netdev->netdev_ops = &netxen_netdev_ops;
+ netdev->watchdog_timeo = 2*HZ;
+
+ netxen_nic_change_mtu(netdev, netdev->mtu);
+
+ SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
+
+ netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+ netdev->features |= (NETIF_F_GRO);
+ netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+ netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ }
+
+ if (adapter->pci_using_dac) {
+ netdev->features |= NETIF_F_HIGHDMA;
+ netdev->vlan_features |= NETIF_F_HIGHDMA;
+ }
+
+ if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX)
+ netdev->features |= (NETIF_F_HW_VLAN_TX);
+
+ netdev->irq = adapter->msix_entries[0].vector;
+
+ err = netxen_napi_add(adapter, netdev);
+ if (err)
+ return err;
+
+ init_timer(&adapter->watchdog_timer);
+ adapter->watchdog_timer.function = &netxen_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+ INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
+ INIT_WORK(&adapter->tx_timeout_task, netxen_reset_task);
+
+ if (netxen_read_mac_addr(adapter))
+ dev_warn(&pdev->dev, "failed to read mac addr\n");
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ err = register_netdev(netdev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register net device\n");
+ return err;
+ }
+
+ return 0;
+}
+
static int __devinit
netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -990,9 +1113,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev = alloc_etherdev(sizeof(struct netxen_adapter));
if(!netdev) {
- printk(KERN_ERR"%s: Failed to allocate memory for the "
- "device block.Check system memory resource"
- " usage.\n", netxen_nic_driver_name);
+ dev_err(&pdev->dev, "failed to allocate net_device\n");
+ err = -ENOMEM;
goto err_out_free_res;
}
@@ -1020,38 +1142,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* This will be reset for mezz cards */
adapter->portnum = pci_func_id;
- adapter->rx_csum = 1;
- adapter->mc_enabled = 0;
- if (NX_IS_REVISION_P3(revision_id))
- adapter->max_mc_count = 38;
- else
- adapter->max_mc_count = 16;
-
- netdev->netdev_ops = &netxen_netdev_ops;
- netdev->watchdog_timeo = 2*HZ;
-
- netxen_nic_change_mtu(netdev, netdev->mtu);
- SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
-
- netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
- netdev->features |= (NETIF_F_GRO);
- netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
-
- if (NX_IS_REVISION_P3(revision_id)) {
- netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- }
-
- if (adapter->pci_using_dac) {
- netdev->features |= NETIF_F_HIGHDMA;
- netdev->vlan_features |= NETIF_F_HIGHDMA;
- }
-
- if (netxen_nic_get_board_info(adapter) != 0) {
- printk("%s: Error getting board config info.\n",
- netxen_nic_driver_name);
- err = -EIO;
+ err = netxen_nic_get_board_info(adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Error getting board config info.\n");
goto err_out_iounmap;
}
@@ -1072,15 +1166,11 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_out_iounmap;
- nx_update_dma_mask(adapter);
-
- netxen_nic_get_firmware_info(adapter);
-
/*
* See if the firmware gave us a virtual-physical port mapping.
*/
adapter->physical_port = adapter->portnum;
- if (adapter->fw_major < 4) {
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
i = NXRD32(adapter, CRB_V2P(adapter->portnum));
if (i != 0x55555555)
adapter->physical_port = i;
@@ -1090,31 +1180,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netxen_setup_intr(adapter);
- netdev->irq = adapter->msix_entries[0].vector;
-
- if (netxen_napi_add(adapter, netdev))
- goto err_out_disable_msi;
-
- init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = &netxen_watchdog;
- adapter->watchdog_timer.data = (unsigned long)adapter;
- INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
- INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
-
- err = netxen_read_mac_addr(adapter);
+ err = netxen_setup_netdev(adapter, netdev);
if (err)
- dev_warn(&pdev->dev, "failed to read mac addr\n");
-
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
-
- if ((err = register_netdev(netdev))) {
- printk(KERN_ERR "%s: register_netdev failed port #%d"
- " aborting\n", netxen_nic_driver_name,
- adapter->portnum);
- err = -EIO;
goto err_out_disable_msi;
- }
pci_set_drvdata(pdev, adapter);
@@ -1134,7 +1202,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_disable_msi:
netxen_teardown_intr(adapter);
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
err_out_iounmap:
netxen_cleanup_pci_map(adapter);
@@ -1164,12 +1232,10 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
- if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
- netxen_nic_detach(adapter);
- }
+ netxen_nic_detach(adapter);
if (adapter->portnum == 0)
- netxen_free_adapter_offload(adapter);
+ netxen_free_dummy_dma(adapter);
netxen_teardown_intr(adapter);
netxen_free_sds_rings(&adapter->recv_ctx);
@@ -1198,8 +1264,7 @@ netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
if (netif_running(netdev))
netxen_nic_down(adapter, netdev);
- if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
- netxen_nic_detach(adapter);
+ netxen_nic_detach(adapter);
pci_save_state(pdev);
@@ -1260,11 +1325,9 @@ static int netxen_nic_open(struct net_device *netdev)
if (adapter->driver_mismatch)
return -EIO;
- if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
- err = netxen_nic_attach(adapter);
- if (err)
- return err;
- }
+ err = netxen_nic_attach(adapter);
+ if (err)
+ return err;
err = netxen_nic_up(adapter, netdev);
if (err)
@@ -1290,30 +1353,52 @@ static int netxen_nic_close(struct net_device *netdev)
return 0;
}
-static bool netxen_tso_check(struct net_device *netdev,
- struct cmd_desc_type0 *desc, struct sk_buff *skb)
+static void
+netxen_tso_check(struct net_device *netdev,
+ struct nx_host_tx_ring *tx_ring,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb)
{
- bool tso = false;
u8 opcode = TX_ETHER_PKT;
__be16 protocol = skb->protocol;
- u16 flags = 0;
+ u16 flags = 0, vid = 0;
+ u32 producer;
+ int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
+ struct cmd_desc_type0 *hwdesc;
+ struct vlan_ethhdr *vh;
if (protocol == cpu_to_be16(ETH_P_8021Q)) {
- struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data;
+
+ vh = (struct vlan_ethhdr *)skb->data;
protocol = vh->h_vlan_encapsulated_proto;
flags = FLAGS_VLAN_TAGGED;
+
+ } else if (vlan_tx_tag_present(skb)) {
+
+ flags = FLAGS_VLAN_OOB;
+ vid = vlan_tx_tag_get(skb);
+ netxen_set_tx_vlan_tci(first_desc, vid);
+ vlan_oob = 1;
}
if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
skb_shinfo(skb)->gso_size > 0) {
- desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- desc->total_hdr_length =
- skb_transport_offset(skb) + tcp_hdrlen(skb);
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+ first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ first_desc->total_hdr_length = hdr_len;
+ if (vlan_oob) {
+ first_desc->total_hdr_length += VLAN_HLEN;
+ first_desc->tcp_hdr_offset = VLAN_HLEN;
+ first_desc->ip_hdr_offset = VLAN_HLEN;
+ /* Only in case of TSO on vlan device */
+ flags |= FLAGS_VLAN_TAGGED;
+ }
opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
TX_TCP_LSO6 : TX_TCP_LSO;
- tso = true;
+ tso = 1;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
u8 l4proto;
@@ -1334,10 +1419,62 @@ static bool netxen_tso_check(struct net_device *netdev,
opcode = TX_UDPV6_PKT;
}
}
- desc->tcp_hdr_offset = skb_transport_offset(skb);
- desc->ip_hdr_offset = skb_network_offset(skb);
- netxen_set_tx_flags_opcode(desc, flags, opcode);
- return tso;
+
+ first_desc->tcp_hdr_offset += skb_transport_offset(skb);
+ first_desc->ip_hdr_offset += skb_network_offset(skb);
+ netxen_set_tx_flags_opcode(first_desc, flags, opcode);
+
+ if (!tso)
+ return;
+
+ /* For LSO, we need to copy the MAC/IP/TCP headers into
+ * the descriptor ring
+ */
+ producer = tx_ring->producer;
+ copied = 0;
+ offset = 2;
+
+ if (vlan_oob) {
+ /* Create a TSO vlan header template for firmware */
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+ hdr_len + VLAN_HLEN);
+
+ vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
+ skb_copy_from_linear_data(skb, vh, 12);
+ vh->h_vlan_proto = htons(ETH_P_8021Q);
+ vh->h_vlan_TCI = htons(vid);
+ skb_copy_from_linear_data_offset(skb, 12,
+ (char *)vh + 16, copy_len - 16);
+
+ copied = copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ while (copied < hdr_len) {
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
+ (hdr_len - copied));
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ skb_copy_from_linear_data_offset(skb, copied,
+ (char *)hwdesc + offset, copy_len);
+
+ copied += copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ tx_ring->producer = producer;
+ barrier();
}
static void
@@ -1361,9 +1498,8 @@ netxen_clean_tx_dma_mapping(struct pci_dev *pdev,
static inline void
netxen_clear_cmddesc(u64 *desc)
{
- int i;
- for (i = 0; i < 8; i++)
- desc[i] = 0ULL;
+ desc[0] = 0ULL;
+ desc[2] = 0ULL;
}
static int
@@ -1371,18 +1507,18 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct netxen_adapter *adapter = netdev_priv(netdev);
struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
- unsigned int first_seg_len = skb->len - skb->data_len;
+ struct skb_frag_struct *frag;
struct netxen_cmd_buffer *pbuf;
struct netxen_skb_frag *buffrag;
- struct cmd_desc_type0 *hwdesc;
- struct pci_dev *pdev = adapter->pdev;
+ struct cmd_desc_type0 *hwdesc, *first_desc;
+ struct pci_dev *pdev;
dma_addr_t temp_dma;
int i, k;
+ unsigned long offset;
u32 producer;
- int frag_count, no_of_desc;
+ int len, frag_count, no_of_desc;
u32 num_txd = tx_ring->num_desc;
- bool is_tso = false;
frag_count = skb_shinfo(skb)->nr_frags + 1;
@@ -1396,32 +1532,30 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
producer = tx_ring->producer;
- hwdesc = &tx_ring->desc_head[producer];
- netxen_clear_cmddesc((u64 *)hwdesc);
- pbuf = &tx_ring->cmd_buf_arr[producer];
+ pdev = adapter->pdev;
+ len = skb->len - skb->data_len;
- is_tso = netxen_tso_check(netdev, hwdesc, skb);
+ temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, temp_dma))
+ goto drop_packet;
+ pbuf = &tx_ring->cmd_buf_arr[producer];
pbuf->skb = skb;
pbuf->frag_count = frag_count;
- buffrag = &pbuf->frag_array[0];
- temp_dma = pci_map_single(pdev, skb->data, first_seg_len,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(pdev, temp_dma))
- goto drop_packet;
+ buffrag = &pbuf->frag_array[0];
buffrag->dma = temp_dma;
- buffrag->length = first_seg_len;
+ buffrag->length = len;
+
+ first_desc = hwdesc = &tx_ring->desc_head[producer];
+ netxen_clear_cmddesc((u64 *)hwdesc);
netxen_set_tx_frags_len(hwdesc, frag_count, skb->len);
netxen_set_tx_port(hwdesc, adapter->portnum);
- hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len);
- hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
+ hwdesc->buffer_length[0] = cpu_to_le16(len);
+ hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
for (i = 1, k = 1; i < frag_count; i++, k++) {
- struct skb_frag_struct *frag;
- int len, temp_len;
- unsigned long offset;
/* move to next desc. if there is a need */
if ((i & 0x3) == 0) {
@@ -1432,11 +1566,11 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
pbuf = &tx_ring->cmd_buf_arr[producer];
pbuf->skb = NULL;
}
+ buffrag = &pbuf->frag_array[i];
frag = &skb_shinfo(skb)->frags[i - 1];
len = frag->size;
offset = frag->page_offset;
- temp_len = len;
temp_dma = pci_map_page(pdev, frag->page, offset,
len, PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(pdev, temp_dma)) {
@@ -1444,11 +1578,10 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
goto drop_packet;
}
- buffrag++;
buffrag->dma = temp_dma;
- buffrag->length = temp_len;
+ buffrag->length = len;
- hwdesc->buffer_length[k] = cpu_to_le16(temp_len);
+ hwdesc->buffer_length[k] = cpu_to_le16(len);
switch (k) {
case 0:
hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
@@ -1463,53 +1596,14 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
hwdesc->addr_buffer4 = cpu_to_le64(temp_dma);
break;
}
- frag++;
- }
- producer = get_next_index(producer, num_txd);
-
- /* For LSO, we need to copy the MAC/IP/TCP headers into
- * the descriptor ring
- */
- if (is_tso) {
- int hdr_len, first_hdr_len, more_hdr;
- hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) {
- first_hdr_len = sizeof(struct cmd_desc_type0) - 2;
- more_hdr = 1;
- } else {
- first_hdr_len = hdr_len;
- more_hdr = 0;
- }
- /* copy the MAC/IP/TCP headers to the cmd descriptor list */
- hwdesc = &tx_ring->desc_head[producer];
- pbuf = &tx_ring->cmd_buf_arr[producer];
- pbuf->skb = NULL;
-
- /* copy the first 64 bytes */
- memcpy(((void *)hwdesc) + 2,
- (void *)(skb->data), first_hdr_len);
- producer = get_next_index(producer, num_txd);
-
- if (more_hdr) {
- hwdesc = &tx_ring->desc_head[producer];
- pbuf = &tx_ring->cmd_buf_arr[producer];
- pbuf->skb = NULL;
- /* copy the next 64 bytes - should be enough except
- * for pathological case
- */
- skb_copy_from_linear_data_offset(skb, first_hdr_len,
- hwdesc,
- (hdr_len -
- first_hdr_len));
- producer = get_next_index(producer, num_txd);
- }
}
+ tx_ring->producer = get_next_index(producer, num_txd);
- tx_ring->producer = producer;
- adapter->stats.txbytes += skb->len;
+ netxen_tso_check(netdev, tx_ring, first_desc, skb);
netxen_nic_update_cmd_producer(adapter, tx_ring);
+ adapter->stats.txbytes += skb->len;
adapter->stats.xmitcalled++;
return NETDEV_TX_OK;
@@ -1641,10 +1735,13 @@ static void netxen_tx_timeout(struct net_device *netdev)
{
struct netxen_adapter *adapter = (struct netxen_adapter *)
netdev_priv(netdev);
+
+ dev_err(&netdev->dev, "transmit timeout, resetting.\n");
+
SCHEDULE_WORK(&adapter->tx_timeout_task);
}
-static void netxen_tx_timeout_task(struct work_struct *work)
+static void netxen_reset_task(struct work_struct *work)
{
struct netxen_adapter *adapter =
container_of(work, struct netxen_adapter, tx_timeout_task);
@@ -1652,9 +1749,6 @@ static void netxen_tx_timeout_task(struct work_struct *work)
if (!netif_running(adapter->netdev))
return;
- printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
- netxen_nic_driver_name, adapter->netdev->name);
-
netxen_napi_disable(adapter);
adapter->netdev->trans_start = jiffies;
@@ -1712,7 +1806,7 @@ static irqreturn_t netxen_intr(int irq, void *data)
}
/* clear interrupt */
- if (adapter->fw_major < 4)
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
netxen_nic_disable_int(sds_ring);
adapter->pci_write_immediate(adapter,
@@ -1781,6 +1875,128 @@ static void netxen_nic_poll_controller(struct net_device *netdev)
}
#endif
+#ifdef CONFIG_INET
+
+#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops)
+
+static int
+netxen_destip_supported(struct netxen_adapter *adapter)
+{
+ if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+ return 0;
+
+ if (adapter->ahw.cut_through)
+ return 0;
+
+ return 1;
+}
+
+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 in_device *indev;
+
+recheck:
+ if (dev == NULL)
+ goto done;
+
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ dev = vlan_dev_real_dev(dev);
+ goto recheck;
+ }
+
+ if (!is_netxen_netdev(dev))
+ goto done;
+
+ adapter = netdev_priv(dev);
+
+ if (!adapter || !netxen_destip_supported(adapter))
+ goto done;
+
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ goto done;
+
+ indev = in_dev_get(dev);
+ if (!indev)
+ goto done;
+
+ for_ifa(indev) {
+ switch (event) {
+ case NETDEV_UP:
+ netxen_config_ipaddr(adapter,
+ ifa->ifa_address, NX_IP_UP);
+ break;
+ case NETDEV_DOWN:
+ netxen_config_ipaddr(adapter,
+ ifa->ifa_address, NX_IP_DOWN);
+ break;
+ default:
+ break;
+ }
+ } endfor_ifa(indev);
+
+ in_dev_put(indev);
+done:
+ return NOTIFY_DONE;
+}
+
+static int
+netxen_inetaddr_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct netxen_adapter *adapter;
+ struct net_device *dev;
+
+ struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
+
+ dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
+
+recheck:
+ if (dev == NULL || !netif_running(dev))
+ goto done;
+
+ if (dev->priv_flags & IFF_802_1Q_VLAN) {
+ dev = vlan_dev_real_dev(dev);
+ goto recheck;
+ }
+
+ if (!is_netxen_netdev(dev))
+ goto done;
+
+ adapter = netdev_priv(dev);
+
+ if (!adapter || !netxen_destip_supported(adapter))
+ goto done;
+
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
+ goto done;
+
+ switch (event) {
+ case NETDEV_UP:
+ netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
+ break;
+ case NETDEV_DOWN:
+ netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
+ break;
+ default:
+ break;
+ }
+
+done:
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block netxen_netdev_cb = {
+ .notifier_call = netxen_netdev_event,
+};
+
+static struct notifier_block netxen_inetaddr_cb = {
+ .notifier_call = netxen_inetaddr_event,
+};
+#endif
+
static struct pci_driver netxen_driver = {
.name = netxen_nic_driver_name,
.id_table = netxen_pci_tbl,
@@ -1792,8 +2008,6 @@ static struct pci_driver netxen_driver = {
#endif
};
-/* Driver Registration on NetXen card */
-
static int __init netxen_init_module(void)
{
printk(KERN_INFO "%s\n", netxen_nic_driver_string);
@@ -1801,6 +2015,11 @@ static int __init netxen_init_module(void)
if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
return -ENOMEM;
+#ifdef CONFIG_INET
+ register_netdevice_notifier(&netxen_netdev_cb);
+ register_inetaddr_notifier(&netxen_inetaddr_cb);
+#endif
+
return pci_register_driver(&netxen_driver);
}
@@ -1809,6 +2028,11 @@ module_init(netxen_init_module);
static void __exit netxen_exit_module(void)
{
pci_unregister_driver(&netxen_driver);
+
+#ifdef CONFIG_INET
+ unregister_inetaddr_notifier(&netxen_inetaddr_cb);
+ unregister_netdevice_notifier(&netxen_netdev_cb);
+#endif
destroy_workqueue(netxen_workq);
}
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 2a8da476ab3..462d20f2643 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -463,7 +463,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
dev->trans_start = jiffies;
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 77d44a06170..a0ac5d4f27d 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -1183,7 +1183,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
if (skb->len > XMIT_BUFF_SIZE) {
printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -1267,7 +1267,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev)
}
dev_kfree_skb(skb);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 1f10ed603e2..81a06178589 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -1216,7 +1216,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&p->ring_lock, flags);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void set_multicast_list(struct net_device *dev)
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 8c1f6988f39..e4a93b8ed48 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -1356,7 +1356,7 @@ static int netdrv_start_xmit (struct sk_buff *skb, struct net_device *dev)
DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
dev->name, skb->data, skb->len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index f35c609ba02..a23aa872404 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -806,7 +806,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pop_tx_status(dev);
spin_unlock_irqrestore(&lp->window_lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 690b9c76d34..d2156ab3da2 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -635,7 +635,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&priv->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The EL3 interrupt handler. */
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 0e38d80fd25..b5cfac7c517 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -1179,7 +1179,7 @@ static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
dev->stats.tx_bytes += send_length;
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 479d5b49437..434d9407bfb 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -865,7 +865,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -924,7 +924,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
dev_kfree_skb (skb);
- return 0;
+ return NETDEV_TX_OK;
} /* fjn_start_xmit */
/*====================================================================*/
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 02ef63ed1f9..0f8118a8257 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -990,7 +990,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} /* mace_start_xmit */
/* ----------------------------------------------------------------------------
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 37e05d3ab89..2f39244c17f 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -1399,7 +1399,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
smc->saved_skb = NULL;
dev->stats.tx_dropped++;
- return 0; /* Do not re-queue this packet. */
+ return NETDEV_TX_OK; /* Do not re-queue this packet. */
}
/* A packet is now waiting. */
smc->packets_waiting++;
@@ -1422,7 +1422,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
smc_hardware_send_packet(dev); /* Send the packet now.. */
spin_unlock_irqrestore(&smc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -1431,7 +1431,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
spin_unlock_irqrestore(&smc->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*======================================================================
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index ef37d22c7e1..eda7bf6047c 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1384,7 +1384,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (pktlen < ETH_ZLEN)
{
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
pktlen = ETH_ZLEN;
}
@@ -1414,7 +1414,7 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev->stats.tx_bytes += pktlen;
netif_start_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/****************
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 1c35e1d637a..955a87ac9af 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -2536,7 +2536,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The PCNET32 interrupt handler. */
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index de9cf5136fd..d5d8e1c5bc9 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -56,6 +56,12 @@ config BROADCOM_PHY
Currently supports the BCM5411, BCM5421, BCM5461, BCM5464, BCM5481
and BCM5482 PHYs.
+config BCM63XX_PHY
+ tristate "Drivers for Broadcom 63xx SOCs internal PHY"
+ depends on BCM63XX
+ ---help---
+ Currently supports the 6348 and 6358 PHYs.
+
config ICPLUS_PHY
tristate "Drivers for ICPlus PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 3a1bfefefbc..edfaac48cbd 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
+obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c
new file mode 100644
index 00000000000..4fed95e8350
--- /dev/null
+++ b/drivers/net/phy/bcm63xx.c
@@ -0,0 +1,132 @@
+/*
+ * Driver for Broadcom 63xx SOCs integrated PHYs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define MII_BCM63XX_IR 0x1a /* interrupt register */
+#define MII_BCM63XX_IR_EN 0x4000 /* global interrupt enable */
+#define MII_BCM63XX_IR_DUPLEX 0x0800 /* duplex changed */
+#define MII_BCM63XX_IR_SPEED 0x0400 /* speed changed */
+#define MII_BCM63XX_IR_LINK 0x0200 /* link changed */
+#define MII_BCM63XX_IR_GMASK 0x0100 /* global interrupt mask */
+
+MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver");
+MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
+MODULE_LICENSE("GPL");
+
+static int bcm63xx_config_init(struct phy_device *phydev)
+{
+ int reg, err;
+
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ /* Mask interrupts globally. */
+ reg |= MII_BCM63XX_IR_GMASK;
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ if (err < 0)
+ return err;
+
+ /* Unmask events we are interested in */
+ reg = ~(MII_BCM63XX_IR_DUPLEX |
+ MII_BCM63XX_IR_SPEED |
+ MII_BCM63XX_IR_LINK) |
+ MII_BCM63XX_IR_EN;
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int bcm63xx_ack_interrupt(struct phy_device *phydev)
+{
+ int reg;
+
+ /* Clear pending interrupts. */
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ return 0;
+}
+
+static int bcm63xx_config_intr(struct phy_device *phydev)
+{
+ int reg, err;
+
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ reg &= ~MII_BCM63XX_IR_GMASK;
+ else
+ reg |= MII_BCM63XX_IR_GMASK;
+
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ return err;
+}
+
+static struct phy_driver bcm63xx_1_driver = {
+ .phy_id = 0x00406000,
+ .phy_id_mask = 0xfffffc00,
+ .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,
+ .config_init = bcm63xx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = bcm63xx_ack_interrupt,
+ .config_intr = bcm63xx_config_intr,
+ .driver = { .owner = THIS_MODULE },
+};
+
+/* same phy as above, with just a different OUI */
+static struct phy_driver bcm63xx_2_driver = {
+ .phy_id = 0x002bdc00,
+ .phy_id_mask = 0xfffffc00,
+ .name = "Broadcom BCM63XX (2)",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = bcm63xx_config_init,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = bcm63xx_ack_interrupt,
+ .config_intr = bcm63xx_config_intr,
+ .driver = { .owner = THIS_MODULE },
+};
+
+static int __init bcm63xx_phy_init(void)
+{
+ int ret;
+
+ ret = phy_driver_register(&bcm63xx_1_driver);
+ if (ret)
+ goto out_63xx_1;
+ ret = phy_driver_register(&bcm63xx_2_driver);
+ if (ret)
+ goto out_63xx_2;
+ return ret;
+
+out_63xx_2:
+ phy_driver_unregister(&bcm63xx_1_driver);
+out_63xx_1:
+ return ret;
+}
+
+static void __exit bcm63xx_phy_exit(void)
+{
+ phy_driver_unregister(&bcm63xx_1_driver);
+ phy_driver_unregister(&bcm63xx_2_driver);
+}
+
+module_init(bcm63xx_phy_init);
+module_exit(bcm63xx_phy_exit);
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 2ca8b0d84ee..00487f569cf 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -990,7 +990,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
schedule_work(&nl->immediate);
spin_unlock_irq(&nl->lock);
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 639d11bc444..d0b965517b4 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -988,12 +988,12 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
skb_queue_tail(&ppp->file.xq, skb);
ppp_xmit_process(ppp);
- return 0;
+ return NETDEV_TX_OK;
outf:
kfree_skb(skb);
++dev->stats.tx_dropped;
- return 0;
+ return NETDEV_TX_OK;
}
static int
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 961b5397a53..840677f5ee8 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -1115,13 +1115,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
}
/* IO Size check */
- if (pci_resource_len(pdev, 0) < io_size) {
+ if (pci_resource_len(pdev, bar) < io_size) {
printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n");
err = -EIO;
goto err_out;
}
- pioaddr = pci_resource_start(pdev, 0); /* IO map base address */
+ pioaddr = pci_resource_start(pdev, bar); /* IO map base address */
pci_set_master(pdev);
dev = alloc_etherdev(sizeof(struct r6040_private));
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 8702e7acdee..bc98e7f69ee 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -114,11 +114,6 @@ static int rionet_rx_clean(struct net_device *ndev)
if (error == NET_RX_DROP) {
ndev->stats.rx_dropped++;
- } else if (error == NET_RX_BAD) {
- if (netif_msg_rx_err(rnet))
- printk(KERN_WARNING "%s: bad rx packet\n",
- DRV_NAME);
- ndev->stats.rx_errors++;
} else {
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE;
@@ -208,7 +203,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
spin_unlock_irqrestore(&rnet->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid,
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 81dbcbb910f..d9553465591 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1466,7 +1466,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&rrpriv->lock, flags);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 458daa06ed4..d4df9330c44 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -4111,14 +4111,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb->len <= 0)) {
DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (!is_s2io_card_up(sp)) {
DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
dev->name);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
queue = 0;
@@ -4192,7 +4192,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
s2io_stop_tx_queue(sp, fifo->fifo_no);
dev_kfree_skb(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
offload_type = s2io_offload_type(skb);
@@ -4304,14 +4304,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
if (sp->config.intr_type == MSI_X)
tx_intr_handler(fifo);
- return 0;
+ return NETDEV_TX_OK;
pci_map_failed:
stats->pci_map_fail_cnt++;
s2io_stop_tx_queue(sp, fifo->fifo_no);
stats->mem_freed += skb->truesize;
dev_kfree_skb(skb);
spin_unlock_irqrestore(&fifo->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index fc0e38bddee..6a81aec645d 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -1086,7 +1086,7 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name);
/* sb1000 can't xmit datagrams */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* SB1000 interrupt handler. */
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index d8c9cf1b901..508551f1b3f 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -2091,7 +2091,7 @@ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&sc->sbm_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/**********************************************************************
@@ -2688,7 +2688,7 @@ static int sbmac_poll(struct napi_struct *napi, int budget)
}
-static int __init sbmac_probe(struct platform_device *pldev)
+static int __devinit sbmac_probe(struct platform_device *pldev)
{
struct net_device *dev;
struct sbmac_softc *sc;
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index ebbbe09725f..7cc8bb81413 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -401,7 +401,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
buf = skb->data;
@@ -415,7 +415,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
/* You might need to clean up and record Tx statistics here. */
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 5fb88ca6dd7..ecf3279fbef 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -594,7 +594,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
len = skb->len;
if (len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
len = ETH_ZLEN;
}
@@ -642,7 +642,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
spin_unlock_irqrestore(&sp->tx_lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static void timeout(struct net_device *dev)
@@ -720,7 +720,7 @@ static const struct net_device_ops sgiseeq_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
-static int __init sgiseeq_probe(struct platform_device *pdev)
+static int __devinit sgiseeq_probe(struct platform_device *pdev)
{
struct sgiseeq_platform_data *pd = pdev->dev.platform_data;
struct hpc3_regs *hpcregs = pd->hpc;
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index a2d82ddb3b4..4c4dcbf1902 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -1133,7 +1133,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
ndev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* device close function */
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index a9a897bb42d..61ceeaaf104 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1628,7 +1628,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
"to slot %d.\n",
net_dev->name, skb->data, (int)skb->len, entry);
- return 0;
+ return NETDEV_TX_OK;
}
/**
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index 088fe26484e..888a14a045e 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -1077,7 +1077,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
// dequeue packets from xmt queue and send them
netif_start_queue(dev);
dev_kfree_skb(skb);
- return (0); /* return "success" */
+ return NETDEV_TX_OK; /* return "success" */
}
if (bp->QueueSkb == 0) { // return with tbusy set: queue full
@@ -1091,7 +1091,7 @@ static int skfp_send_pkt(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
} // skfp_send_pkt
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 3550c5dcd93..661abd0492a 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -4117,7 +4117,7 @@ static int sky2_debug_show(struct seq_file *seq, void *v)
seq_printf(seq, "\nRx ring hw get=%d put=%d last=%d\n",
sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_GET_IDX)),
- last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
+ sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX)));
sky2_read32(hw, B0_Y2_SP_LISR);
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 5c61d5fad90..899c4a2112c 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -484,12 +484,12 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&sl->lock);
printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (sl->tty == NULL) {
spin_unlock(&sl->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
sl_lock(sl);
@@ -498,7 +498,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock(&sl->lock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index bc4976ac871..2a6b6de9533 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -553,7 +553,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_dropped++;
spin_unlock_irqrestore(&lp->lock, flags);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#ifdef SMC_USE_DMA
@@ -566,7 +566,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
lp->pending_tx_skb = skb;
netif_stop_queue(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
DBG(SMC_DEBUG_TX | SMC_DEBUG_DMA, "%s: Activating Tx DMA\n", dev->name);
lp->txdma_active = 1;
@@ -577,7 +577,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
smc911x_hardware_send_pkt(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index e02471b2f2b..0a1b6f40108 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -512,7 +512,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
length = ETH_ZLEN;
}
@@ -534,7 +534,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
lp->saved_skb = NULL;
/* this IS an error, but, i don't want the skb saved */
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/* either way, a packet is waiting now */
lp->packets_waiting++;
@@ -571,12 +571,12 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
SMC_ENABLE_INT( IM_ALLOC_INT );
PRINTK2((CARDNAME": memory allocation deferred. \n"));
/* it's deferred, but I'll handle it later */
- return 0;
+ return NETDEV_TX_OK;
}
/* or YES! I can send the packet now.. */
smc_hardware_send_packet(dev);
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 1c70e999cc5..0f2c52c2e04 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -655,7 +655,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
smc_special_lock(&lp->lock);
@@ -692,7 +692,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
smc_hardware_send_pkt((unsigned long)dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index 753a1fba460..9599ce77ef8 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -211,7 +211,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
length = skb->len;
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -265,7 +265,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 838cce8b8ff..1018349a29d 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1311,7 +1311,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index 7bb27426dbd..2f1eaaf7a72 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -1015,7 +1015,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
if(skb->len > XMIT_BUFF_SIZE)
{
printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -1110,7 +1110,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
#endif
}
- return 0;
+ return NETDEV_TX_OK;
}
/*******************************************
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 534dfe3eef6..0ca4241b4f6 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -562,7 +562,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
netif_start_queue(dev);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
@@ -648,7 +648,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
local_irq_restore(flags);
- return 0;
+ return NETDEV_TX_OK;
}
/* The LANCE interrupt handler. */
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 5017d7fcb40..536cf7e06bf 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -984,7 +984,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *bigmac_get_stats(struct net_device *dev)
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 545f81b34ad..0df6332ed9c 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -1091,7 +1091,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
"%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* Reset hardware tx and free all of tx buffers */
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 4ef729198e1..008bd59fc64 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2338,7 +2338,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *happy_meal_get_stats(struct net_device *dev)
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index afc7b351e5e..9d6fd4760ea 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1163,7 +1163,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* taken from the depca driver */
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index c6ec61e0acc..dcefb608a9f 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -621,7 +621,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void qe_set_multicast(struct net_device *dev)
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index d737f6b8f87..1ce2da172ca 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1509,7 +1509,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
*/
spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
#define FATAL_ERROR_INT \
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 384cb5e2839..70c9ec45d8f 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -1095,11 +1095,11 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n",
dev->name );
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (skb_padto(skb, TLAN_MIN_FRAME_SIZE))
- return 0;
+ return NETDEV_TX_OK;
txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE);
tail_list = priv->txList + priv->txTail;
@@ -1150,7 +1150,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS );
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
} /* TLan_StartTx */
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index b40b6de2d08..1787d52941b 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -1240,7 +1240,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ;
- return 0;
+ return NETDEV_TX_OK;
} else {
spin_unlock_irqrestore(&xl_priv->xl_lock,flags) ;
return NETDEV_TX_BUSY;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 08a6c41c159..96d00c8f8d3 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -1041,7 +1041,7 @@ static int tok_send_packet(struct sk_buff *skb, struct net_device *dev)
writeb(CMD_IN_SRB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD);
spin_unlock_irqrestore(&(ti->lock), flags);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/*****************************************************************************/
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index b3715efdce5..d07e61a9499 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -1183,7 +1183,7 @@ static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
netif_stop_queue(dev);
spin_unlock_irqrestore(&streamer_priv->streamer_lock,flags);
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 451b54136ed..f73f4e684f3 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -1052,7 +1052,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev)
writew((((readw(olympic_mmio+TXENQ_1)) & 0x8000) ^ 0x8000) | 1,olympic_mmio+TXENQ_1);
netif_wake_queue(dev);
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
- return 0;
+ return NETDEV_TX_OK;
} else {
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
return NETDEV_TX_BUSY;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 54ad4ed0337..6515894c83f 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -4609,7 +4609,7 @@ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev)
if(tp->QueueSkb > 0)
netif_wake_queue(dev);
- return (0);
+ return NETDEV_TX_OK;
}
static int smctr_send_lobe_media_test(struct net_device *dev)
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index a2eab72b507..07f6dfd3ba0 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -682,7 +682,7 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device
tms380tr_exec_sifcmd(dev, CMD_TX_VALID);
spin_unlock_irqrestore(&tp->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 81f054dbb88..769af558a34 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -651,7 +651,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev)
dw32(TxPoll, NormalTxPoll);
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
/* Set or clear the multicast filter for this adaptor.
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 8e78f003f08..5e15fab58c1 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -676,7 +676,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
if (skb->len > MAX_PACKET_SIZE) {
printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&db->lock, flags);
@@ -722,7 +722,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 2abb5d3becc..9d46638d250 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -690,7 +690,7 @@ tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
- return 0;
+ return NETDEV_TX_OK;
}
static void tulip_clean_tx_ring(struct tulip_private *tp)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 9277ce8febe..9074a34eb81 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -582,7 +582,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len > MAX_PACKET_SIZE) {
printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&db->lock, flags);
@@ -624,7 +624,7 @@ static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* free this SKB */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 842b1a2c40d..6bc7540b216 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1058,7 +1058,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, np->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void netdev_tx_done(struct net_device *dev)
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index c2ca9f40e40..22b6a239fb3 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -434,7 +434,7 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->transmit_used = nextdescriptor;
leave("xircom-start_xmit - sent");
spin_unlock_irqrestore(&card->lock,flags);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 027f7aba26a..a998b6a9c24 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -398,12 +398,12 @@ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
if (tun->flags & TUN_FASYNC)
kill_fasync(&tun->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&tun->socket.wait);
- return 0;
+ return NETDEV_TX_OK;
drop:
dev->stats.tx_dropped++;
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void tun_net_mclist(struct net_device *dev)
@@ -641,6 +641,9 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
case VIRTIO_NET_HDR_GSO_TCPV6:
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
break;
+ case VIRTIO_NET_HDR_GSO_UDP:
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+ break;
default:
tun->dev->stats.rx_frame_errors++;
kfree_skb(skb);
@@ -726,6 +729,8 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ else if (sinfo->gso_type & SKB_GSO_UDP)
+ gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
if (sinfo->gso_type & SKB_GSO_TCP_ECN)
@@ -997,7 +1002,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
goto err_free_sk;
}
- err = -EINVAL;
err = register_netdevice(tun->dev);
if (err < 0)
goto err_free_sk;
@@ -1074,7 +1078,8 @@ static int set_offload(struct net_device *dev, unsigned long arg)
old_features = dev->features;
/* Unset features, set them as we chew on the arg. */
features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST
- |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6));
+ |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6
+ |NETIF_F_UFO));
if (arg & TUN_F_CSUM) {
features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
@@ -1091,6 +1096,11 @@ static int set_offload(struct net_device *dev, unsigned long arg)
features |= NETIF_F_TSO6;
arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
}
+
+ if (arg & TUN_F_UFO) {
+ features |= NETIF_F_UFO;
+ arg &= ~TUN_F_UFO;
+ }
}
/* This gives the user a way to test for new features in future by
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index cf25eb41b1c..2c26b4577e8 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -909,7 +909,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
netif_wake_queue(dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
static void
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 3b957e6412e..52a6750b820 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -209,9 +209,10 @@ static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth,
{
struct sk_buff *skb = NULL;
- skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
- UCC_GETH_RX_DATA_BUF_ALIGNMENT);
-
+ skb = __skb_dequeue(&ugeth->rx_recycle);
+ if (!skb)
+ skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT);
if (skb == NULL)
return NULL;
@@ -1986,6 +1987,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
iounmap(ugeth->ug_regs);
ugeth->ug_regs = NULL;
}
+
+ skb_queue_purge(&ugeth->rx_recycle);
}
static void ucc_geth_set_multi(struct net_device *dev)
@@ -2202,6 +2205,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth)
return -ENOMEM;
}
+ skb_queue_head_init(&ugeth->rx_recycle);
+
return 0;
}
@@ -3173,7 +3178,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
spin_unlock_irq(&ugeth->lock);
- return 0;
+ return NETDEV_TX_OK;
}
static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
@@ -3208,8 +3213,10 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
if (netif_msg_rx_err(ugeth))
ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
__func__, __LINE__, (u32) skb);
- if (skb)
- dev_kfree_skb_any(skb);
+ if (skb) {
+ skb->data = skb->head + NET_SKB_PAD;
+ __skb_queue_head(&ugeth->rx_recycle, skb);
+ }
ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
dev->stats.rx_dropped++;
@@ -3267,6 +3274,8 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
/* Normal processing. */
while ((bd_status & T_R) == 0) {
+ struct sk_buff *skb;
+
/* BD contains already transmitted buffer. */
/* Handle the transmitted buffer and release */
/* the BD to be used with the current frame */
@@ -3276,9 +3285,16 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
dev->stats.tx_packets++;
- /* Free the sk buffer associated with this TxBD */
- dev_kfree_skb(ugeth->
- tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]);
+ skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]];
+
+ if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN &&
+ skb_recycle_check(skb,
+ ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT))
+ __skb_queue_head(&ugeth->rx_recycle, skb);
+ else
+ dev_kfree_skb(skb);
+
ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
ugeth->skb_dirtytx[txQ] =
(ugeth->skb_dirtytx[txQ] +
@@ -3307,16 +3323,16 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget)
ug_info = ugeth->ug_info;
- howmany = 0;
- for (i = 0; i < ug_info->numQueuesRx; i++)
- howmany += ucc_geth_rx(ugeth, i, budget - howmany);
-
/* Tx event processing */
spin_lock(&ugeth->lock);
for (i = 0; i < ug_info->numQueuesTx; i++)
ucc_geth_tx(ugeth->ndev, i);
spin_unlock(&ugeth->lock);
+ howmany = 0;
+ for (i = 0; i < ug_info->numQueuesRx; i++)
+ howmany += ucc_geth_rx(ugeth, i, budget - howmany);
+
if (howmany < budget) {
napi_complete(napi);
setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS);
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index 195ab267ead..cfb31afc08a 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -1212,6 +1212,8 @@ struct ucc_geth_private {
/* index of the first skb which hasn't been transmitted yet. */
u16 skb_dirtytx[NUM_TX_QUEUES];
+ struct sk_buff_head rx_recycle;
+
struct ugeth_mii_info *mii_info;
struct phy_device *phydev;
phy_interface_t phy_interface;
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index b9dd4257428..7abdc4abbe0 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -448,7 +448,7 @@ static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void catc_tx_timeout(struct net_device *netdev)
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index f8c6d7ea726..ffe41063573 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -780,7 +780,7 @@ static int hso_net_start_xmit(struct sk_buff *skb, struct net_device *net)
netif_stop_queue(net);
if (hso_get_activity(odev->parent) == -EAGAIN) {
odev->skb_tx_buf = skb;
- return 0;
+ return NETDEV_TX_OK;
}
/* log if asked */
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 1f9ec29fce5..200fe3d525c 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -829,7 +829,7 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth->stats.tx_errors++;
netif_start_queue(net);
spin_unlock_irq(&kaweth->device_lock);
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -864,7 +864,7 @@ skip:
spin_unlock_irq(&kaweth->device_lock);
- return 0;
+ return NETDEV_TX_OK;
}
/****************************************************************
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 631d269ac98..69d2df95ac8 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -914,7 +914,7 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index fcc6fa0905d..bac8b77fb25 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -753,7 +753,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
}
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index edfd9e10ceb..25e435c4904 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -575,7 +575,9 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
int usbnet_stop (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
+ struct driver_info *info = dev->driver_info;
int temp;
+ int retval;
DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup);
DECLARE_WAITQUEUE (wait, current);
@@ -587,6 +589,18 @@ int usbnet_stop (struct net_device *net)
net->stats.rx_errors, net->stats.tx_errors
);
+ /* allow minidriver to stop correctly (wireless devices to turn off
+ * radio etc) */
+ if (info->stop) {
+ retval = info->stop(dev);
+ if (retval < 0 && netif_msg_ifdown(dev))
+ devinfo(dev,
+ "stop fail (%d) usbnet usb-%s-%s, %s",
+ retval,
+ dev->udev->bus->bus_name, dev->udev->devpath,
+ info->description);
+ }
+
// ensure there are no more active urbs
add_wait_queue (&unlink_wakeup, &wait);
dev->wait = &unlink_wakeup;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 1097c72e44d..190f784c9cf 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -171,6 +171,7 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len > (rcv->mtu + MTU_PAD))
goto rx_drop;
+ skb->tstamp.tv64 = 0;
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, rcv);
if (dev->features & NETIF_F_NO_CSUM)
@@ -189,17 +190,17 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
rcv_stats->rx_packets++;
netif_rx(skb);
- return 0;
+ return NETDEV_TX_OK;
tx_drop:
kfree_skb(skb);
stats->tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
rx_drop:
kfree_skb(skb);
rcv_stats->rx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 88c30a58b4b..46eb618bbc9 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1226,7 +1226,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
entry = rp->cur_tx % TX_RING_SIZE;
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
rp->tx_skbuff[entry] = skb;
@@ -1238,7 +1238,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
rp->tx_skbuff[entry] = NULL;
dev->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/* Padding is not copied and so must be redone. */
@@ -1286,7 +1286,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
dev->name, rp->cur_tx-1, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 3ba35956327..47be41a39d3 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -61,9 +61,9 @@
#include <linux/interrupt.h>
#include <linux/string.h>
#include <linux/wait.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/if.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/inetdevice.h>
#include <linux/reboot.h>
@@ -81,7 +81,7 @@
#include "via-velocity.h"
-static int velocity_nics = 0;
+static int velocity_nics;
static int msglevel = MSG_LEVEL_INFO;
/**
@@ -92,8 +92,7 @@ static int msglevel = MSG_LEVEL_INFO;
* Fetch the mask bits of the selected CAM and store them into the
* provided mask buffer.
*/
-
-static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_get_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
@@ -111,7 +110,6 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
/* Select mar */
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
}
@@ -122,8 +120,7 @@ static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
*
* Store a new mask into a CAM
*/
-
-static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
/* Select CAM mask */
@@ -131,9 +128,9 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
writeb(CAMADDR_CAMEN, &regs->CAMADDR);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++)
writeb(*mask++, &(regs->MARCAM[i]));
- }
+
/* disable CAMEN */
writeb(0, &regs->CAMADDR);
@@ -141,7 +138,7 @@ static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
}
-static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+static void mac_set_vlan_cam_mask(struct mac_regs __iomem *regs, u8 *mask)
{
int i;
/* Select CAM mask */
@@ -149,9 +146,9 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 8; i++)
writeb(*mask++, &(regs->MARCAM[i]));
- }
+
/* disable CAMEN */
writeb(0, &regs->CAMADDR);
@@ -167,8 +164,7 @@ static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
*
* Load an address or vlan tag into a CAM
*/
-
-static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
+static void mac_set_cam(struct mac_regs __iomem *regs, int idx, const u8 *addr)
{
int i;
@@ -179,9 +175,9 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
writeb(*addr++, &(regs->MARCAM[i]));
- }
+
BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
udelay(10);
@@ -192,7 +188,7 @@ static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
}
-static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
+static void mac_set_vlan_cam(struct mac_regs __iomem *regs, int idx,
const u8 *addr)
{
@@ -223,8 +219,7 @@ static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
* reset the Wake on lan features. This function doesn't restore
* the rest of the logic from the result of sleep/wakeup
*/
-
-static void mac_wol_reset(struct mac_regs __iomem * regs)
+static void mac_wol_reset(struct mac_regs __iomem *regs)
{
/* Turn off SWPTAG right after leaving power mode */
@@ -242,7 +237,6 @@ static void mac_wol_reset(struct mac_regs __iomem * regs)
writew(0xFFFF, &regs->WOLSRClr);
}
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
static const struct ethtool_ops velocity_ethtool_ops;
/*
@@ -253,10 +247,10 @@ MODULE_AUTHOR("VIA Networking Technologies, Inc.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("VIA Networking Velocity Family Gigabit Ethernet Adapter Driver");
-#define VELOCITY_PARAM(N,D) \
- static int N[MAX_UNITS]=OPTION_DEFAULT;\
+#define VELOCITY_PARAM(N, D) \
+ static int N[MAX_UNITS] = OPTION_DEFAULT;\
module_param_array(N, int, NULL, 0); \
- MODULE_PARM_DESC(N, D);
+ MODULE_PARM_DESC(N, D);
#define RX_DESC_MIN 64
#define RX_DESC_MAX 255
@@ -336,8 +330,8 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
4: indicate 10Mbps full duplex mode
Note:
- if EEPROM have been set to the force mode, this option is ignored
- by driver.
+ if EEPROM have been set to the force mode, this option is ignored
+ by driver.
*/
VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
@@ -370,76 +364,14 @@ static int rx_copybreak = 200;
module_param(rx_copybreak, int, 0644);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
- const struct velocity_info_tbl *info);
-static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
-static void velocity_print_info(struct velocity_info *vptr);
-static int velocity_open(struct net_device *dev);
-static int velocity_change_mtu(struct net_device *dev, int mtu);
-static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t velocity_intr(int irq, void *dev_instance);
-static void velocity_set_multi(struct net_device *dev);
-static struct net_device_stats *velocity_get_stats(struct net_device *dev);
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static int velocity_close(struct net_device *dev);
-static int velocity_receive_frame(struct velocity_info *, int idx);
-static int velocity_alloc_rx_buf(struct velocity_info *, int idx);
-static void velocity_free_rd_ring(struct velocity_info *vptr);
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
-static int velocity_soft_reset(struct velocity_info *vptr);
-static void mii_init(struct velocity_info *vptr, u32 mii_status);
-static u32 velocity_get_link(struct net_device *dev);
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
-static void velocity_print_link_status(struct velocity_info *vptr);
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
-static void velocity_shutdown(struct velocity_info *vptr);
-static void enable_flow_control_ability(struct velocity_info *vptr);
-static void enable_mii_autopoll(struct mac_regs __iomem * regs);
-static int velocity_mii_read(struct mac_regs __iomem *, u8 byIdx, u16 * pdata);
-static int velocity_mii_write(struct mac_regs __iomem *, u8 byMiiAddr, u16 data);
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs);
-static u32 check_connection_type(struct mac_regs __iomem * regs);
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
-
#ifdef CONFIG_PM
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state);
-static int velocity_resume(struct pci_dev *pdev);
-
static DEFINE_SPINLOCK(velocity_dev_list_lock);
static LIST_HEAD(velocity_dev_list);
-
-#endif
-
-#if defined(CONFIG_PM) && defined(CONFIG_INET)
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr);
-
-static struct notifier_block velocity_inetaddr_notifier = {
- .notifier_call = velocity_netdev_event,
-};
-
-static void velocity_register_notifier(void)
-{
- register_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-static void velocity_unregister_notifier(void)
-{
- unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
-}
-
-#else
-
-#define velocity_register_notifier() do {} while (0)
-#define velocity_unregister_notifier() do {} while (0)
-
#endif
/*
* Internal board variants. At the moment we have only one
*/
-
static struct velocity_info_tbl chip_info_table[] = {
{CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
{ }
@@ -449,7 +381,6 @@ 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 const struct pci_device_id velocity_id_table[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
{ }
@@ -464,7 +395,6 @@ MODULE_DEVICE_TABLE(pci, velocity_id_table);
* Given a chip identifier return a suitable description. Returns
* a pointer a static string valid while the driver is loaded.
*/
-
static const char __devinit *get_chip_name(enum chip_type chip_id)
{
int i;
@@ -482,7 +412,6 @@ static const char __devinit *get_chip_name(enum chip_type chip_id)
* unload for each active device that is present. Disconnects
* the device from the network layer and frees all the resources
*/
-
static void __devexit velocity_remove1(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
@@ -520,7 +449,6 @@ static void __devexit velocity_remove1(struct pci_dev *pdev)
* all the verification and checking as well as reporting so that
* we don't duplicate code for each option.
*/
-
static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max, int def, char *name, const char *devname)
{
if (val == -1)
@@ -549,8 +477,7 @@ static void __devinit velocity_set_int_opt(int *opt, int val, int min, int max,
* all the verification and checking as well as reporting so that
* we don't duplicate code for each option.
*/
-
-static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 flag, char *name, const char *devname)
+static void __devinit velocity_set_bool_opt(u32 *opt, int val, int def, u32 flag, char *name, const char *devname)
{
(*opt) &= (~flag);
if (val == -1)
@@ -575,7 +502,6 @@ static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 fla
* Turn the module and command options into a single structure
* for the current device
*/
-
static void __devinit velocity_get_options(struct velocity_opt *opts, int index, const char *devname)
{
@@ -601,10 +527,9 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index,
* Initialize the content addressable memory used for filters. Load
* appropriately according to the presence of VLAN
*/
-
static void velocity_init_cam_filter(struct velocity_info *vptr)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -647,19 +572,19 @@ static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
{
struct velocity_info *vptr = netdev_priv(dev);
- spin_lock_irq(&vptr->lock);
+ spin_lock_irq(&vptr->lock);
velocity_init_cam_filter(vptr);
- spin_unlock_irq(&vptr->lock);
+ spin_unlock_irq(&vptr->lock);
}
static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct velocity_info *vptr = netdev_priv(dev);
- spin_lock_irq(&vptr->lock);
+ spin_lock_irq(&vptr->lock);
vlan_group_set_device(vptr->vlgrp, vid, NULL);
velocity_init_cam_filter(vptr);
- spin_unlock_irq(&vptr->lock);
+ spin_unlock_irq(&vptr->lock);
}
static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
@@ -674,11 +599,10 @@ static void velocity_init_rx_ring_indexes(struct velocity_info *vptr)
* Reset the ownership and status for the receive ring side.
* Hand all the receive queue to the NIC.
*/
-
static void velocity_rx_reset(struct velocity_info *vptr)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
int i;
velocity_init_rx_ring_indexes(vptr);
@@ -696,6 +620,647 @@ static void velocity_rx_reset(struct velocity_info *vptr)
}
/**
+ * velocity_get_opt_media_mode - get media selection
+ * @vptr: velocity adapter
+ *
+ * Get the media mode stored in EEPROM or module options and load
+ * mii_status accordingly. The requested link state information
+ * is also returned.
+ */
+static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
+{
+ u32 status = 0;
+
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_AUTO:
+ status = VELOCITY_AUTONEG_ENABLE;
+ break;
+ case SPD_DPX_100_FULL:
+ status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
+ break;
+ case SPD_DPX_10_FULL:
+ status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
+ break;
+ case SPD_DPX_100_HALF:
+ status = VELOCITY_SPEED_100;
+ break;
+ case SPD_DPX_10_HALF:
+ status = VELOCITY_SPEED_10;
+ break;
+ }
+ vptr->mii_status = status;
+ return status;
+}
+
+/**
+ * safe_disable_mii_autopoll - autopoll off
+ * @regs: velocity registers
+ *
+ * Turn off the autopoll and wait for it to disable on the chip
+ */
+static void safe_disable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+ u16 ww;
+
+ /* turn off MAUTO */
+ writeb(0, &regs->MIICR);
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(1);
+ if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+}
+
+/**
+ * enable_mii_autopoll - turn on autopolling
+ * @regs: velocity registers
+ *
+ * Enable the MII link status autopoll feature on the Velocity
+ * hardware. Wait for it to enable.
+ */
+static void enable_mii_autopoll(struct mac_regs __iomem *regs)
+{
+ int ii;
+
+ writeb(0, &(regs->MIICR));
+ writeb(MIIADR_SWMPL, &regs->MIIADR);
+
+ for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+ udelay(1);
+ if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+
+ writeb(MIICR_MAUTO, &regs->MIICR);
+
+ for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
+ udelay(1);
+ if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
+ break;
+ }
+
+}
+
+/**
+ * velocity_mii_read - read MII data
+ * @regs: velocity registers
+ * @index: MII register index
+ * @data: buffer for received data
+ *
+ * Perform a single read of an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
+{
+ u16 ww;
+
+ /*
+ * Disable MIICR_MAUTO, so that mii addr can be set normally
+ */
+ safe_disable_mii_autopoll(regs);
+
+ writeb(index, &regs->MIIADR);
+
+ BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ if (!(readb(&regs->MIICR) & MIICR_RCMD))
+ break;
+ }
+
+ *data = readw(&regs->MIIDATA);
+
+ enable_mii_autopoll(regs);
+ if (ww == W_MAX_TIMEOUT)
+ return -ETIMEDOUT;
+ return 0;
+}
+
+
+/**
+ * mii_check_media_mode - check media state
+ * @regs: velocity registers
+ *
+ * Check the current MII status and determine the link status
+ * accordingly
+ */
+static u32 mii_check_media_mode(struct mac_regs __iomem *regs)
+{
+ u32 status = 0;
+ u16 ANAR;
+
+ if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
+ status |= VELOCITY_LINK_FAIL;
+
+ if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
+ status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+ else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
+ status |= (VELOCITY_SPEED_1000);
+ else {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if (ANAR & ANAR_TXFD)
+ status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
+ else if (ANAR & ANAR_TX)
+ status |= VELOCITY_SPEED_100;
+ else if (ANAR & ANAR_10FD)
+ status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
+ else
+ status |= (VELOCITY_SPEED_10);
+ }
+
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+ == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+ if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+ status |= VELOCITY_AUTONEG_ENABLE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * velocity_mii_write - write MII data
+ * @regs: velocity registers
+ * @index: MII register index
+ * @data: 16bit data for the MII register
+ *
+ * Perform a single write to an MII 16bit register. Returns zero
+ * on success or -ETIMEDOUT if the PHY did not respond.
+ */
+static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
+{
+ u16 ww;
+
+ /*
+ * Disable MIICR_MAUTO, so that mii addr can be set normally
+ */
+ safe_disable_mii_autopoll(regs);
+
+ /* MII reg offset */
+ writeb(mii_addr, &regs->MIIADR);
+ /* set MII data */
+ writew(data, &regs->MIIDATA);
+
+ /* turn on MIICR_WCMD */
+ BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+
+ /* W_MAX_TIMEOUT is the timeout period */
+ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
+ udelay(5);
+ if (!(readb(&regs->MIICR) & MIICR_WCMD))
+ break;
+ }
+ enable_mii_autopoll(regs);
+
+ if (ww == W_MAX_TIMEOUT)
+ return -ETIMEDOUT;
+ return 0;
+}
+
+/**
+ * set_mii_flow_control - flow control setup
+ * @vptr: velocity interface
+ *
+ * Set up the flow control on this interface according to
+ * the supplied user/eeprom options.
+ */
+static void set_mii_flow_control(struct velocity_info *vptr)
+{
+ /*Enable or Disable PAUSE in ANAR */
+ switch (vptr->options.flow_cntl) {
+ case FLOW_CNTL_TX:
+ MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_RX:
+ MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_TX_RX:
+ MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+
+ case FLOW_CNTL_DISABLE:
+ MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * mii_set_auto_on - autonegotiate on
+ * @vptr: velocity
+ *
+ * Enable autonegotation on this interface
+ */
+static void mii_set_auto_on(struct velocity_info *vptr)
+{
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
+ MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+ else
+ MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+}
+
+static u32 check_connection_type(struct mac_regs __iomem *regs)
+{
+ u32 status = 0;
+ u8 PHYSR0;
+ u16 ANAR;
+ PHYSR0 = readb(&regs->PHYSR0);
+
+ /*
+ if (!(PHYSR0 & PHYSR0_LINKGD))
+ status|=VELOCITY_LINK_FAIL;
+ */
+
+ if (PHYSR0 & PHYSR0_FDPX)
+ status |= VELOCITY_DUPLEX_FULL;
+
+ if (PHYSR0 & PHYSR0_SPDG)
+ status |= VELOCITY_SPEED_1000;
+ else if (PHYSR0 & PHYSR0_SPD10)
+ status |= VELOCITY_SPEED_10;
+ else
+ status |= VELOCITY_SPEED_100;
+
+ if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
+ velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
+ if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
+ == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
+ if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
+ status |= VELOCITY_AUTONEG_ENABLE;
+ }
+ }
+
+ return status;
+}
+
+
+
+/**
+ * velocity_set_media_mode - set media mode
+ * @mii_status: old MII link state
+ *
+ * Check the media link state and configure the flow control
+ * PHY and also velocity hardware setup accordingly. In particular
+ * we need to set up CD polling and frame bursting.
+ */
+static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+{
+ u32 curr_status;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+
+ vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
+ curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+
+ /* Set mii link status */
+ set_mii_flow_control(vptr);
+
+ /*
+ Check if new status is consisent with current status
+ if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
+ || (mii_status==curr_status)) {
+ vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
+ vptr->mii_status=check_connection_type(vptr->mac_regs);
+ VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
+ return 0;
+ }
+ */
+
+ if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+ MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
+
+ /*
+ * If connection type is AUTO
+ */
+ if (mii_status & VELOCITY_AUTONEG_ENABLE) {
+ VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
+ /* clear force MAC mode bit */
+ BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ /* set duplex mode of MAC according to duplex mode of MII */
+ MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
+ MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+ MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+
+ /* enable AUTO-NEGO mode */
+ mii_set_auto_on(vptr);
+ } else {
+ u16 ANAR;
+ u8 CHIPGCR;
+
+ /*
+ * 1. if it's 3119, disable frame bursting in halfduplex mode
+ * and enable it in fullduplex mode
+ * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
+ * 3. only enable CD heart beat counter in 10HD mode
+ */
+
+ /* set force MAC mode bit */
+ BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+ CHIPGCR = readb(&regs->CHIPGCR);
+ CHIPGCR &= ~CHIPGCR_FCGMII;
+
+ if (mii_status & VELOCITY_DUPLEX_FULL) {
+ CHIPGCR |= CHIPGCR_FCFDX;
+ writeb(CHIPGCR, &regs->CHIPGCR);
+ VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
+ if (vptr->rev_id < REV_ID_VT3216_A0)
+ BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+ } else {
+ CHIPGCR &= ~CHIPGCR_FCFDX;
+ VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
+ writeb(CHIPGCR, &regs->CHIPGCR);
+ if (vptr->rev_id < REV_ID_VT3216_A0)
+ BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+ }
+
+ MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+
+ if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
+ BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+ else
+ BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+
+ /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
+ velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
+ ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
+ if (mii_status & VELOCITY_SPEED_100) {
+ if (mii_status & VELOCITY_DUPLEX_FULL)
+ ANAR |= ANAR_TXFD;
+ else
+ ANAR |= ANAR_TX;
+ } else {
+ if (mii_status & VELOCITY_DUPLEX_FULL)
+ ANAR |= ANAR_10FD;
+ else
+ ANAR |= ANAR_10;
+ }
+ velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
+ /* enable AUTO-NEGO mode */
+ mii_set_auto_on(vptr);
+ /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+ }
+ /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
+ /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
+ return VELOCITY_LINK_CHANGE;
+}
+
+/**
+ * velocity_print_link_status - link status reporting
+ * @vptr: velocity to report on
+ *
+ * Turn the link status of the velocity card into a kernel log
+ * description of the new link state, detailing speed and duplex
+ * status
+ */
+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);
+ } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+
+ if (vptr->mii_status & VELOCITY_SPEED_1000)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
+ else if (vptr->mii_status & VELOCITY_SPEED_100)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
+ else
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
+ else
+ VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
+ } else {
+ VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
+ switch (vptr->options.spd_dpx) {
+ case SPD_DPX_100_HALF:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
+ break;
+ case SPD_DPX_100_FULL:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
+ break;
+ case SPD_DPX_10_HALF:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
+ break;
+ case SPD_DPX_10_FULL:
+ VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ * enable_flow_control_ability - flow control
+ * @vptr: veloity to configure
+ *
+ * Set up flow control according to the flow control options
+ * determined by the eeprom/configuration.
+ */
+static void enable_flow_control_ability(struct velocity_info *vptr)
+{
+
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+
+ switch (vptr->options.flow_cntl) {
+
+ case FLOW_CNTL_DEFAULT:
+ if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ else
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+
+ if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ else
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_TX:
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_RX:
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ case FLOW_CNTL_TX_RX:
+ writel(CR0_FDXTFCEN, &regs->CR0Set);
+ writel(CR0_FDXRFCEN, &regs->CR0Set);
+ break;
+
+ case FLOW_CNTL_DISABLE:
+ writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ writel(CR0_FDXTFCEN, &regs->CR0Clr);
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+/**
+ * velocity_soft_reset - soft reset
+ * @vptr: velocity to reset
+ *
+ * Kick off a soft reset of the velocity adapter and then poll
+ * until the reset sequence has completed before returning.
+ */
+static int velocity_soft_reset(struct velocity_info *vptr)
+{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int i = 0;
+
+ writel(CR0_SFRST, &regs->CR0Set);
+
+ for (i = 0; i < W_MAX_TIMEOUT; i++) {
+ udelay(5);
+ if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
+ break;
+ }
+
+ if (i == W_MAX_TIMEOUT) {
+ writel(CR0_FORSRST, &regs->CR0Set);
+ /* FIXME: PCI POSTING */
+ /* delay 2ms */
+ mdelay(2);
+ }
+ return 0;
+}
+
+/**
+ * velocity_set_multi - filter list change callback
+ * @dev: network device
+ *
+ * Called by the network layer when the filter lists need to change
+ * for a velocity adapter. Reload the CAMs with the new address
+ * filter ruleset.
+ */
+static void velocity_set_multi(struct net_device *dev)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ u8 rx_mode;
+ int i;
+ struct dev_mc_list *mclist;
+
+ if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
+ writel(0xffffffff, &regs->MARCAM[0]);
+ writel(0xffffffff, &regs->MARCAM[4]);
+ rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
+ } else if ((dev->mc_count > vptr->multicast_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ writel(0xffffffff, &regs->MARCAM[0]);
+ writel(0xffffffff, &regs->MARCAM[4]);
+ rx_mode = (RCR_AM | RCR_AB);
+ } else {
+ int offset = MCAM_SIZE - vptr->multicast_limit;
+ mac_get_cam_mask(regs, vptr->mCAMmask);
+
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+ mac_set_cam(regs, i + offset, mclist->dmi_addr);
+ vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
+ }
+
+ mac_set_cam_mask(regs, vptr->mCAMmask);
+ rx_mode = RCR_AM | RCR_AB | RCR_AP;
+ }
+ if (dev->mtu > 1500)
+ rx_mode |= RCR_AL;
+
+ BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+
+}
+
+/*
+ * MII access , media link mode setting functions
+ */
+
+/**
+ * mii_init - set up MII
+ * @vptr: velocity adapter
+ * @mii_status: links tatus
+ *
+ * Set up the PHY for the current link state.
+ */
+static void mii_init(struct velocity_info *vptr, u32 mii_status)
+{
+ u16 BMCR;
+
+ switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
+ case PHYID_CICADA_CS8201:
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ /*
+ * Turn on ECHODIS bit in NWay-forced full mode and turn it
+ * off it in NWay-forced half mode for NWay-forced v.s.
+ * legacy-forced issue.
+ */
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ /*
+ * Turn on Link/Activity LED enable bit for CIS8201
+ */
+ MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
+ break;
+ case PHYID_VT3216_32BIT:
+ case PHYID_VT3216_64BIT:
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ /*
+ * Turn on ECHODIS bit in NWay-forced full mode and turn it
+ * off it in NWay-forced half mode for NWay-forced v.s.
+ * legacy-forced issue
+ */
+ if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
+ MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ else
+ MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
+ break;
+
+ case PHYID_MARVELL_1000:
+ case PHYID_MARVELL_1000S:
+ /*
+ * Assert CRS on Transmit
+ */
+ MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
+ /*
+ * Reset to hardware default
+ */
+ MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
+ break;
+ default:
+ ;
+ }
+ velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
+ if (BMCR & BMCR_ISO) {
+ BMCR &= ~BMCR_ISO;
+ velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+ }
+}
+
+
+/**
* velocity_init_registers - initialise MAC registers
* @vptr: velocity to init
* @type: type of initialisation (hot or cold)
@@ -703,11 +1268,10 @@ static void velocity_rx_reset(struct velocity_info *vptr)
* Initialise the MAC on a reset or on first set up on the
* hardware.
*/
-
static void velocity_init_registers(struct velocity_info *vptr,
enum velocity_init_type type)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
int i, mii_status;
mac_wol_reset(regs);
@@ -750,9 +1314,9 @@ static void velocity_init_registers(struct velocity_info *vptr,
mdelay(5);
mac_eeprom_reload(regs);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 6; i++)
writeb(vptr->dev->dev_addr[i], &(regs->PAR[i]));
- }
+
/*
* clear Pre_ACPI bit.
*/
@@ -819,291 +1383,29 @@ static void velocity_init_registers(struct velocity_info *vptr,
}
}
-/**
- * velocity_soft_reset - soft reset
- * @vptr: velocity to reset
- *
- * Kick off a soft reset of the velocity adapter and then poll
- * until the reset sequence has completed before returning.
- */
-
-static int velocity_soft_reset(struct velocity_info *vptr)
-{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int i = 0;
-
- writel(CR0_SFRST, &regs->CR0Set);
-
- for (i = 0; i < W_MAX_TIMEOUT; i++) {
- udelay(5);
- if (!DWORD_REG_BITS_IS_ON(CR0_SFRST, &regs->CR0Set))
- break;
- }
-
- if (i == W_MAX_TIMEOUT) {
- writel(CR0_FORSRST, &regs->CR0Set);
- /* FIXME: PCI POSTING */
- /* delay 2ms */
- mdelay(2);
- }
- return 0;
-}
-
-static const struct net_device_ops velocity_netdev_ops = {
- .ndo_open = velocity_open,
- .ndo_stop = velocity_close,
- .ndo_start_xmit = velocity_xmit,
- .ndo_get_stats = velocity_get_stats,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_set_multicast_list = velocity_set_multi,
- .ndo_change_mtu = velocity_change_mtu,
- .ndo_do_ioctl = velocity_ioctl,
- .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid,
- .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid,
- .ndo_vlan_rx_register = velocity_vlan_rx_register,
-};
-
-/**
- * velocity_found1 - set up discovered velocity card
- * @pdev: PCI device
- * @ent: PCI device table entry that matched
- *
- * Configure a discovered adapter from scratch. Return a negative
- * errno error code on failure paths.
- */
-
-static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void velocity_give_many_rx_descs(struct velocity_info *vptr)
{
- static int first = 1;
- struct net_device *dev;
- 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;
-
- /* FIXME: this driver, like almost all other ethernet drivers,
- * can support more than MAX_UNITS.
- */
- if (velocity_nics >= MAX_UNITS) {
- dev_notice(&pdev->dev, "already found %d NICs.\n",
- velocity_nics);
- return -ENODEV;
- }
-
- dev = alloc_etherdev(sizeof(struct velocity_info));
- if (!dev) {
- dev_err(&pdev->dev, "allocate net device failed.\n");
- goto out;
- }
-
- /* Chain it all together */
-
- SET_NETDEV_DEV(dev, &pdev->dev);
- vptr = netdev_priv(dev);
-
-
- if (first) {
- printk(KERN_INFO "%s Ver. %s\n",
- VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
- printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
- printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
- first = 0;
- }
-
- velocity_init_info(pdev, vptr, info);
-
- vptr->dev = dev;
-
- dev->irq = pdev->irq;
-
- ret = pci_enable_device(pdev);
- if (ret < 0)
- goto err_free_dev;
-
- ret = velocity_get_pci_info(vptr, pdev);
- if (ret < 0) {
- /* error message already printed */
- goto err_disable;
- }
-
- ret = pci_request_regions(pdev, VELOCITY_NAME);
- if (ret < 0) {
- dev_err(&pdev->dev, "No PCI resources.\n");
- goto err_disable;
- }
-
- regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
- if (regs == NULL) {
- ret = -EIO;
- goto err_release_res;
- }
-
- vptr->mac_regs = regs;
-
- mac_wol_reset(regs);
-
- dev->base_addr = vptr->ioaddr;
-
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = readb(&regs->PAR[i]);
-
-
- drv_string = dev_driver_string(&pdev->dev);
-
- velocity_get_options(&vptr->options, velocity_nics, drv_string);
-
- /*
- * Mask out the options cannot be set to the chip
- */
-
- vptr->options.flags &= info->flags;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int avail, dirty, unusable;
/*
- * Enable the chip specified capbilities
+ * RD number must be equal to 4X per hardware spec
+ * (programming guide rev 1.20, p.13)
*/
+ if (vptr->rx.filled < 4)
+ return;
- vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
-
- vptr->wol_opts = vptr->options.wol_opts;
- vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-
- vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
-
- dev->irq = pdev->irq;
- dev->netdev_ops = &velocity_netdev_ops;
- dev->ethtool_ops = &velocity_ethtool_ops;
-
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- dev->features |= NETIF_F_SG;
-#endif
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
- NETIF_F_HW_VLAN_RX;
-
- if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
- dev->features |= NETIF_F_IP_CSUM;
-
- ret = register_netdev(dev);
- if (ret < 0)
- goto err_iounmap;
-
- if (!velocity_get_link(dev)) {
- netif_carrier_off(dev);
- vptr->mii_status |= VELOCITY_LINK_FAIL;
- }
-
- velocity_print_info(vptr);
- pci_set_drvdata(pdev, dev);
-
- /* and leave the chip powered down */
-
- pci_set_power_state(pdev, PCI_D3hot);
-#ifdef CONFIG_PM
- {
- unsigned long flags;
-
- spin_lock_irqsave(&velocity_dev_list_lock, flags);
- list_add(&vptr->list, &velocity_dev_list);
- spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
- }
-#endif
- 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);
- goto out;
-}
-
-/**
- * velocity_print_info - per driver data
- * @vptr: velocity
- *
- * Print per driver data as the kernel driver finds Velocity
- * hardware
- */
-
-static void __devinit velocity_print_info(struct velocity_info *vptr)
-{
- struct net_device *dev = vptr->dev;
-
- printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
- printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
- dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-}
-
-/**
- * velocity_init_info - init private data
- * @pdev: PCI device
- * @vptr: Velocity info
- * @info: Board type
- *
- * Set up the initial velocity_info struct for the device that has been
- * discovered.
- */
-
-static void __devinit velocity_init_info(struct pci_dev *pdev,
- 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;
- spin_lock_init(&vptr->lock);
- INIT_LIST_HEAD(&vptr->list);
-}
-
-/**
- * velocity_get_pci_info - retrieve PCI info for device
- * @vptr: velocity device
- * @pdev: PCI device it matches
- *
- * Retrieve the PCI configuration space data that interests us from
- * the kernel PCI layer
- */
-
-static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
-{
- vptr->rev_id = pdev->revision;
-
- pci_set_master(pdev);
-
- vptr->ioaddr = pci_resource_start(pdev, 0);
- vptr->memaddr = pci_resource_start(pdev, 1);
-
- if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
- dev_err(&pdev->dev,
- "region #0 is not an I/O resource, aborting.\n");
- return -EINVAL;
- }
-
- if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
- dev_err(&pdev->dev,
- "region #1 is an I/O resource, aborting.\n");
- return -EINVAL;
- }
+ wmb();
- if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
- dev_err(&pdev->dev, "region #1 is too small.\n");
- return -EINVAL;
+ unusable = vptr->rx.filled & 0x0003;
+ dirty = vptr->rx.dirty - unusable;
+ for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
+ dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
+ vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
}
- vptr->pdev = pdev;
- return 0;
+ writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
+ vptr->rx.filled = unusable;
}
/**
@@ -1113,7 +1415,6 @@ static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pc
* Allocate PCI mapped DMA rings for the receive and transmit layer
* to use.
*/
-
static int velocity_init_dma_rings(struct velocity_info *vptr)
{
struct velocity_opt *opt = &vptr->options;
@@ -1154,46 +1455,50 @@ static int velocity_init_dma_rings(struct velocity_info *vptr)
return 0;
}
+static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
+{
+ vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
+}
+
/**
- * velocity_free_dma_rings - free PCI ring pointers
- * @vptr: Velocity to free from
+ * velocity_alloc_rx_buf - allocate aligned receive buffer
+ * @vptr: velocity
+ * @idx: ring index
*
- * Clean up the PCI ring buffers allocated to this velocity.
+ * Allocate a new full sized buffer for the reception of a frame and
+ * map it into PCI space for the hardware to use. The hardware
+ * requires *64* byte alignment of the buffer which makes life
+ * less fun than would be ideal.
*/
-
-static void velocity_free_dma_rings(struct velocity_info *vptr)
+static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
{
- 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);
-}
+ struct rx_desc *rd = &(vptr->rx.ring[idx]);
+ struct velocity_rd_info *rd_info = &(vptr->rx.info[idx]);
-static void velocity_give_many_rx_descs(struct velocity_info *vptr)
-{
- struct mac_regs __iomem *regs = vptr->mac_regs;
- int avail, dirty, unusable;
+ rd_info->skb = dev_alloc_skb(vptr->rx.buf_sz + 64);
+ if (rd_info->skb == NULL)
+ return -ENOMEM;
/*
- * RD number must be equal to 4X per hardware spec
- * (programming guide rev 1.20, p.13)
+ * Do the gymnastics to get the buffer head for data at
+ * 64byte alignment.
*/
- if (vptr->rx.filled < 4)
- return;
-
- wmb();
+ skb_reserve(rd_info->skb, (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);
- unusable = vptr->rx.filled & 0x0003;
- dirty = vptr->rx.dirty - unusable;
- for (avail = vptr->rx.filled & 0xfffc; avail; avail--) {
- dirty = (dirty > 0) ? dirty - 1 : vptr->options.numrx - 1;
- vptr->rx.ring[dirty].rdesc0.len |= OWNED_BY_NIC;
- }
+ /*
+ * Fill in the descriptor to match
+ */
- writew(vptr->rx.filled & 0xfffc, &regs->RBRDU);
- vptr->rx.filled = unusable;
+ *((u32 *) & (rd->rdesc0)) = 0;
+ rd->size = cpu_to_le16(vptr->rx.buf_sz) | RX_INTEN;
+ rd->pa_low = cpu_to_le32(rd_info->skb_dma);
+ rd->pa_high = 0;
+ return 0;
}
+
static int velocity_rx_refill(struct velocity_info *vptr)
{
int dirty = vptr->rx.dirty, done = 0;
@@ -1221,42 +1526,6 @@ static int velocity_rx_refill(struct velocity_info *vptr)
return done;
}
-static void velocity_set_rxbufsize(struct velocity_info *vptr, int mtu)
-{
- vptr->rx.buf_sz = (mtu <= ETH_DATA_LEN) ? PKT_BUF_SZ : mtu + 32;
-}
-
-/**
- * velocity_init_rd_ring - set up receive ring
- * @vptr: velocity to configure
- *
- * Allocate and set up the receive buffers for each ring slot and
- * assign them to the network adapter.
- */
-
-static int velocity_init_rd_ring(struct velocity_info *vptr)
-{
- int ret = -ENOMEM;
-
- vptr->rx.info = kcalloc(vptr->options.numrx,
- sizeof(struct velocity_rd_info), GFP_KERNEL);
- if (!vptr->rx.info)
- goto out;
-
- velocity_init_rx_ring_indexes(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);
- velocity_free_rd_ring(vptr);
- goto out;
- }
-
- ret = 0;
-out:
- return ret;
-}
-
/**
* velocity_free_rd_ring - free receive ring
* @vptr: velocity to clean up
@@ -1264,7 +1533,6 @@ out:
* Free the receive buffers for each ring slot and any
* attached socket buffers that need to go away.
*/
-
static void velocity_free_rd_ring(struct velocity_info *vptr)
{
int i;
@@ -1292,6 +1560,38 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
vptr->rx.info = NULL;
}
+
+
+/**
+ * velocity_init_rd_ring - set up receive ring
+ * @vptr: velocity to configure
+ *
+ * Allocate and set up the receive buffers for each ring slot and
+ * assign them to the network adapter.
+ */
+static int velocity_init_rd_ring(struct velocity_info *vptr)
+{
+ int ret = -ENOMEM;
+
+ vptr->rx.info = kcalloc(vptr->options.numrx,
+ sizeof(struct velocity_rd_info), GFP_KERNEL);
+ if (!vptr->rx.info)
+ goto out;
+
+ velocity_init_rx_ring_indexes(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);
+ velocity_free_rd_ring(vptr);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
/**
* velocity_init_td_ring - set up transmit ring
* @vptr: velocity
@@ -1300,7 +1600,6 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
* Returns zero on success or a negative posix errno code for
* failure.
*/
-
static int velocity_init_td_ring(struct velocity_info *vptr)
{
dma_addr_t curr;
@@ -1314,7 +1613,7 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
sizeof(struct velocity_td_info),
GFP_KERNEL);
if (!vptr->tx.infos[j]) {
- while(--j >= 0)
+ while (--j >= 0)
kfree(vptr->tx.infos[j]);
return -ENOMEM;
}
@@ -1324,22 +1623,92 @@ static int velocity_init_td_ring(struct velocity_info *vptr)
return 0;
}
+/**
+ * velocity_free_dma_rings - free PCI ring pointers
+ * @vptr: Velocity to free from
+ *
+ * Clean up the PCI ring buffers allocated to this velocity.
+ */
+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);
+}
+
+
+static int velocity_init_rings(struct velocity_info *vptr, int mtu)
+{
+ int ret;
+
+ velocity_set_rxbufsize(vptr, mtu);
+
+ ret = velocity_init_dma_rings(vptr);
+ if (ret < 0)
+ goto out;
+
+ ret = velocity_init_rd_ring(vptr);
+ if (ret < 0)
+ goto err_free_dma_rings_0;
+
+ ret = velocity_init_td_ring(vptr);
+ if (ret < 0)
+ goto err_free_rd_ring_1;
+out:
+ return ret;
+
+err_free_rd_ring_1:
+ velocity_free_rd_ring(vptr);
+err_free_dma_rings_0:
+ velocity_free_dma_rings(vptr);
+ goto out;
+}
+
+/**
+ * velocity_free_tx_buf - free transmit buffer
+ * @vptr: velocity
+ * @tdinfo: buffer
+ *
+ * Release an transmit buffer. If the buffer was preallocated then
+ * recycle it, if not then unmap the buffer.
+ */
+static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
+{
+ struct sk_buff *skb = tdinfo->skb;
+ int i;
+ int pktlen;
+
+ /*
+ * Don't unmap the pre-allocated tx_bufs
+ */
+ if (tdinfo->skb_dma) {
+
+ pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
+ for (i = 0; i < tdinfo->nskb_dma; i++) {
+ pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
+ tdinfo->skb_dma[i] = 0;
+ }
+ }
+ dev_kfree_skb_irq(skb);
+ tdinfo->skb = NULL;
+}
+
+
/*
* FIXME: could we merge this with velocity_free_tx_buf ?
*/
-
static void velocity_free_td_ring_entry(struct velocity_info *vptr,
int q, int n)
{
- struct velocity_td_info * td_info = &(vptr->tx.infos[q][n]);
+ struct velocity_td_info *td_info = &(vptr->tx.infos[q][n]);
int i;
if (td_info == NULL)
return;
if (td_info->skb) {
- for (i = 0; i < td_info->nskb_dma; i++)
- {
+ 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);
@@ -1358,7 +1727,6 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr,
* Free up the transmit ring for this particular velocity adapter.
* We free the ring contents but not the ring itself.
*/
-
static void velocity_free_td_ring(struct velocity_info *vptr)
{
int i, j;
@@ -1366,70 +1734,175 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
for (j = 0; j < vptr->tx.numq; j++) {
if (vptr->tx.infos[j] == NULL)
continue;
- for (i = 0; i < vptr->options.numtx; i++) {
+ for (i = 0; i < vptr->options.numtx; i++)
velocity_free_td_ring_entry(vptr, j, i);
- }
kfree(vptr->tx.infos[j]);
vptr->tx.infos[j] = NULL;
}
}
+
+static void velocity_free_rings(struct velocity_info *vptr)
+{
+ velocity_free_td_ring(vptr);
+ velocity_free_rd_ring(vptr);
+ velocity_free_dma_rings(vptr);
+}
+
/**
- * velocity_rx_srv - service RX interrupt
+ * velocity_error - handle error from controller
* @vptr: velocity
- * @status: adapter status (unused)
+ * @status: card status
+ *
+ * Process an error report from the hardware and attempt to recover
+ * the card itself. At the moment we cannot recover from some
+ * theoretically impossible errors but this could be fixed using
+ * the pci_device_failed logic to bounce the hardware
*
- * Walk the receive ring of the velocity adapter and remove
- * any received packets from the receive queue. Hand the ring
- * slots back to the adapter for reuse.
*/
-
-static int velocity_rx_srv(struct velocity_info *vptr, int status)
+static void velocity_error(struct velocity_info *vptr, int status)
{
- struct net_device_stats *stats = &vptr->dev->stats;
- int rd_curr = vptr->rx.curr;
- int works = 0;
- do {
- struct rx_desc *rd = vptr->rx.ring + rd_curr;
+ if (status & ISR_TXSTLI) {
+ struct mac_regs __iomem *regs = vptr->mac_regs;
- if (!vptr->rx.info[rd_curr].skb)
- break;
+ 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);
- if (rd->rdesc0.len & OWNED_BY_NIC)
- break;
+ /* FIXME: port over the pci_device_failed code and use it
+ here */
+ }
- rmb();
+ if (status & ISR_SRCI) {
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int linked;
+
+ if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+ vptr->mii_status = check_connection_type(regs);
+ /*
+ * If it is a 3119, disable frame bursting in
+ * halfduplex mode and enable it in fullduplex
+ * mode
+ */
+ if (vptr->rev_id < REV_ID_VT3216_A0) {
+ if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
+ BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
+ else
+ BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
+ }
+ /*
+ * Only enable CD heart beat counter in 10HD mode
+ */
+ if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10))
+ BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
+ else
+ BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
+ }
/*
- * Don't drop CE or RL error frame although RXOK is off
+ * Get link status from PHYSR0
*/
- if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
- if (velocity_receive_frame(vptr, rd_curr) < 0)
- stats->rx_dropped++;
- } else {
- if (rd->rdesc0.RSR & RSR_CRC)
- stats->rx_crc_errors++;
- if (rd->rdesc0.RSR & RSR_FAE)
- stats->rx_frame_errors++;
+ linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
- stats->rx_dropped++;
+ if (linked) {
+ vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+ netif_carrier_on(vptr->dev);
+ } else {
+ vptr->mii_status |= VELOCITY_LINK_FAIL;
+ netif_carrier_off(vptr->dev);
}
- rd->size |= RX_INTEN;
+ velocity_print_link_status(vptr);
+ enable_flow_control_ability(vptr);
- rd_curr++;
- if (rd_curr >= vptr->options.numrx)
- rd_curr = 0;
- } while (++works <= 15);
+ /*
+ * Re-enable auto-polling because SRCI will disable
+ * auto-polling
+ */
- vptr->rx.curr = rd_curr;
+ enable_mii_autopoll(regs);
- if ((works > 0) && (velocity_rx_refill(vptr) > 0))
- velocity_give_many_rx_descs(vptr);
+ if (vptr->mii_status & VELOCITY_LINK_FAIL)
+ netif_stop_queue(vptr->dev);
+ else
+ netif_wake_queue(vptr->dev);
- VAR_USED(stats);
+ };
+ if (status & ISR_MIBFI)
+ velocity_update_hw_mibs(vptr);
+ if (status & ISR_LSTEI)
+ mac_rx_queue_wake(vptr->mac_regs);
+}
+
+/**
+ * tx_srv - transmit interrupt service
+ * @vptr; Velocity
+ * @status:
+ *
+ * Scan the queues looking for transmitted packets that
+ * we can complete and clean up. Update any statistics as
+ * necessary/
+ */
+static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+{
+ struct tx_desc *td;
+ int qnum;
+ int full = 0;
+ int idx;
+ int works = 0;
+ struct velocity_td_info *tdinfo;
+ struct net_device_stats *stats = &vptr->dev->stats;
+
+ for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
+ for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
+ idx = (idx + 1) % vptr->options.numtx) {
+
+ /*
+ * Get Tx Descriptor
+ */
+ td = &(vptr->tx.rings[qnum][idx]);
+ tdinfo = &(vptr->tx.infos[qnum][idx]);
+
+ if (td->tdesc0.len & OWNED_BY_NIC)
+ break;
+
+ if ((works++ > 15))
+ break;
+
+ if (td->tdesc0.TSR & TSR0_TERR) {
+ stats->tx_errors++;
+ stats->tx_dropped++;
+ if (td->tdesc0.TSR & TSR0_CDH)
+ stats->tx_heartbeat_errors++;
+ if (td->tdesc0.TSR & TSR0_CRS)
+ stats->tx_carrier_errors++;
+ if (td->tdesc0.TSR & TSR0_ABT)
+ stats->tx_aborted_errors++;
+ if (td->tdesc0.TSR & TSR0_OWC)
+ stats->tx_window_errors++;
+ } else {
+ stats->tx_packets++;
+ stats->tx_bytes += tdinfo->skb->len;
+ }
+ velocity_free_tx_buf(vptr, tdinfo);
+ vptr->tx.used[qnum]--;
+ }
+ vptr->tx.tail[qnum] = idx;
+
+ if (AVAIL_TD(vptr, qnum) < 1)
+ full = 1;
+ }
+ /*
+ * Look to see if we should kick the transmit network
+ * layer for more work.
+ */
+ if (netif_queue_stopped(vptr->dev) && (full == 0)
+ && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
+ netif_wake_queue(vptr->dev);
+ }
return works;
}
@@ -1441,7 +1914,6 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
* Process the status bits for the received packet and determine
* if the checksum was computed and verified by the hardware
*/
-
static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
{
skb->ip_summed = CHECKSUM_NONE;
@@ -1450,9 +1922,8 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
if (rd->rdesc1.CSM & CSM_IPOK) {
if ((rd->rdesc1.CSM & CSM_TCPKT) ||
(rd->rdesc1.CSM & CSM_UDPKT)) {
- if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
+ if (!(rd->rdesc1.CSM & CSM_TUPOK))
return;
- }
}
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -1509,6 +1980,7 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
}
}
+
/**
* velocity_receive_frame - received packet processor
* @vptr: velocity we are handling
@@ -1517,7 +1989,6 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
* A packet has arrived. We process the packet and if appropriate
* pass the frame up the network stack
*/
-
static int velocity_receive_frame(struct velocity_info *vptr, int idx)
{
void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
@@ -1579,320 +2050,118 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
return 0;
}
-/**
- * velocity_alloc_rx_buf - allocate aligned receive buffer
- * @vptr: velocity
- * @idx: ring index
- *
- * Allocate a new full sized buffer for the reception of a frame and
- * map it into PCI space for the hardware to use. The hardware
- * requires *64* byte alignment of the buffer which makes life
- * less fun than would be ideal.
- */
-
-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 = dev_alloc_skb(vptr->rx.buf_sz + 64);
- if (rd_info->skb == NULL)
- return -ENOMEM;
-
- /*
- * Do the gymnastics to get the buffer head for data at
- * 64byte alignment.
- */
- skb_reserve(rd_info->skb, (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);
-
- /*
- * Fill in the descriptor to match
- */
-
- *((u32 *) & (rd->rdesc0)) = 0;
- rd->size = cpu_to_le16(vptr->rx.buf_sz) | RX_INTEN;
- rd->pa_low = cpu_to_le32(rd_info->skb_dma);
- rd->pa_high = 0;
- return 0;
-}
/**
- * tx_srv - transmit interrupt service
- * @vptr; Velocity
- * @status:
+ * velocity_rx_srv - service RX interrupt
+ * @vptr: velocity
+ * @status: adapter status (unused)
*
- * Scan the queues looking for transmitted packets that
- * we can complete and clean up. Update any statistics as
- * necessary/
+ * Walk the receive ring of the velocity adapter and remove
+ * any received packets from the receive queue. Hand the ring
+ * slots back to the adapter for reuse.
*/
-
-static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
+static int velocity_rx_srv(struct velocity_info *vptr, int status)
{
- struct tx_desc *td;
- int qnum;
- int full = 0;
- int idx;
- int works = 0;
- struct velocity_td_info *tdinfo;
struct net_device_stats *stats = &vptr->dev->stats;
+ int rd_curr = vptr->rx.curr;
+ int works = 0;
- for (qnum = 0; qnum < vptr->tx.numq; qnum++) {
- for (idx = vptr->tx.tail[qnum]; vptr->tx.used[qnum] > 0;
- idx = (idx + 1) % vptr->options.numtx) {
+ do {
+ struct rx_desc *rd = vptr->rx.ring + rd_curr;
- /*
- * Get Tx Descriptor
- */
- td = &(vptr->tx.rings[qnum][idx]);
- tdinfo = &(vptr->tx.infos[qnum][idx]);
+ if (!vptr->rx.info[rd_curr].skb)
+ break;
- if (td->tdesc0.len & OWNED_BY_NIC)
- break;
+ if (rd->rdesc0.len & OWNED_BY_NIC)
+ break;
- if ((works++ > 15))
- break;
+ rmb();
- if (td->tdesc0.TSR & TSR0_TERR) {
- stats->tx_errors++;
- stats->tx_dropped++;
- if (td->tdesc0.TSR & TSR0_CDH)
- stats->tx_heartbeat_errors++;
- if (td->tdesc0.TSR & TSR0_CRS)
- stats->tx_carrier_errors++;
- if (td->tdesc0.TSR & TSR0_ABT)
- stats->tx_aborted_errors++;
- if (td->tdesc0.TSR & TSR0_OWC)
- stats->tx_window_errors++;
- } else {
- stats->tx_packets++;
- stats->tx_bytes += tdinfo->skb->len;
- }
- velocity_free_tx_buf(vptr, tdinfo);
- vptr->tx.used[qnum]--;
- }
- vptr->tx.tail[qnum] = idx;
+ /*
+ * Don't drop CE or RL error frame although RXOK is off
+ */
+ if (rd->rdesc0.RSR & (RSR_RXOK | RSR_CE | RSR_RL)) {
+ if (velocity_receive_frame(vptr, rd_curr) < 0)
+ stats->rx_dropped++;
+ } else {
+ if (rd->rdesc0.RSR & RSR_CRC)
+ stats->rx_crc_errors++;
+ if (rd->rdesc0.RSR & RSR_FAE)
+ stats->rx_frame_errors++;
- if (AVAIL_TD(vptr, qnum) < 1) {
- full = 1;
+ stats->rx_dropped++;
}
- }
- /*
- * Look to see if we should kick the transmit network
- * layer for more work.
- */
- if (netif_queue_stopped(vptr->dev) && (full == 0)
- && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) {
- netif_wake_queue(vptr->dev);
- }
- return works;
-}
-/**
- * velocity_print_link_status - link status reporting
- * @vptr: velocity to report on
- *
- * Turn the link status of the velocity card into a kernel log
- * description of the new link state, detailing speed and duplex
- * status
- */
+ rd->size |= RX_INTEN;
-static void velocity_print_link_status(struct velocity_info *vptr)
-{
+ rd_curr++;
+ if (rd_curr >= vptr->options.numrx)
+ rd_curr = 0;
+ } while (++works <= 15);
- if (vptr->mii_status & VELOCITY_LINK_FAIL) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: failed to detect cable link\n", vptr->dev->name);
- } else if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link auto-negotiation", vptr->dev->name);
+ vptr->rx.curr = rd_curr;
- if (vptr->mii_status & VELOCITY_SPEED_1000)
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps");
- else if (vptr->mii_status & VELOCITY_SPEED_100)
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps");
- else
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps");
+ if ((works > 0) && (velocity_rx_refill(vptr) > 0))
+ velocity_give_many_rx_descs(vptr);
- if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
- VELOCITY_PRT(MSG_LEVEL_INFO, " full duplex\n");
- else
- VELOCITY_PRT(MSG_LEVEL_INFO, " half duplex\n");
- } else {
- VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
- switch (vptr->options.spd_dpx) {
- case SPD_DPX_100_HALF:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
- break;
- case SPD_DPX_100_FULL:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps full duplex\n");
- break;
- case SPD_DPX_10_HALF:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps half duplex\n");
- break;
- case SPD_DPX_10_FULL:
- VELOCITY_PRT(MSG_LEVEL_INFO, " speed 10M bps full duplex\n");
- break;
- default:
- break;
- }
- }
+ VAR_USED(stats);
+ return works;
}
+
/**
- * velocity_error - handle error from controller
- * @vptr: velocity
- * @status: card status
- *
- * Process an error report from the hardware and attempt to recover
- * the card itself. At the moment we cannot recover from some
- * theoretically impossible errors but this could be fixed using
- * the pci_device_failed logic to bounce the hardware
+ * velocity_intr - interrupt callback
+ * @irq: interrupt number
+ * @dev_instance: interrupting device
*
+ * Called whenever an interrupt is generated by the velocity
+ * adapter IRQ line. We may not be the source of the interrupt
+ * and need to identify initially if we are, and if not exit as
+ * efficiently as possible.
*/
-
-static void velocity_error(struct velocity_info *vptr, int status)
+static irqreturn_t velocity_intr(int irq, void *dev_instance)
{
+ struct net_device *dev = dev_instance;
+ struct velocity_info *vptr = netdev_priv(dev);
+ u32 isr_status;
+ int max_count = 0;
- if (status & ISR_TXSTLI) {
- struct mac_regs __iomem * regs = vptr->mac_regs;
- 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);
+ spin_lock(&vptr->lock);
+ isr_status = mac_read_isr(vptr->mac_regs);
- /* FIXME: port over the pci_device_failed code and use it
- here */
+ /* Not us ? */
+ if (isr_status == 0) {
+ spin_unlock(&vptr->lock);
+ return IRQ_NONE;
}
- if (status & ISR_SRCI) {
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int linked;
-
- if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
- vptr->mii_status = check_connection_type(regs);
-
- /*
- * If it is a 3119, disable frame bursting in
- * halfduplex mode and enable it in fullduplex
- * mode
- */
- if (vptr->rev_id < REV_ID_VT3216_A0) {
- if (vptr->mii_status | VELOCITY_DUPLEX_FULL)
- BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
- else
- BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
- }
- /*
- * Only enable CD heart beat counter in 10HD mode
- */
- if (!(vptr->mii_status & VELOCITY_DUPLEX_FULL) && (vptr->mii_status & VELOCITY_SPEED_10)) {
- BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
- } else {
- BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
- }
- }
- /*
- * Get link status from PHYSR0
- */
- linked = readb(&regs->PHYSR0) & PHYSR0_LINKGD;
-
- if (linked) {
- vptr->mii_status &= ~VELOCITY_LINK_FAIL;
- netif_carrier_on(vptr->dev);
- } else {
- vptr->mii_status |= VELOCITY_LINK_FAIL;
- netif_carrier_off(vptr->dev);
- }
-
- velocity_print_link_status(vptr);
- enable_flow_control_ability(vptr);
-
- /*
- * Re-enable auto-polling because SRCI will disable
- * auto-polling
- */
-
- enable_mii_autopoll(regs);
-
- if (vptr->mii_status & VELOCITY_LINK_FAIL)
- netif_stop_queue(vptr->dev);
- else
- netif_wake_queue(vptr->dev);
-
- };
- if (status & ISR_MIBFI)
- velocity_update_hw_mibs(vptr);
- if (status & ISR_LSTEI)
- mac_rx_queue_wake(vptr->mac_regs);
-}
-
-/**
- * velocity_free_tx_buf - free transmit buffer
- * @vptr: velocity
- * @tdinfo: buffer
- *
- * Release an transmit buffer. If the buffer was preallocated then
- * recycle it, if not then unmap the buffer.
- */
-
-static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
-{
- struct sk_buff *skb = tdinfo->skb;
- int i;
- int pktlen;
+ mac_disable_int(vptr->mac_regs);
/*
- * Don't unmap the pre-allocated tx_bufs
+ * Keep processing the ISR until we have completed
+ * processing and the isr_status becomes zero
*/
- if (tdinfo->skb_dma) {
- pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
- for (i = 0; i < tdinfo->nskb_dma; i++) {
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE);
-#else
- pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
-#endif
- tdinfo->skb_dma[i] = 0;
+ while (isr_status != 0) {
+ mac_write_isr(vptr->mac_regs, isr_status);
+ if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
+ velocity_error(vptr, isr_status);
+ if (isr_status & (ISR_PRXI | ISR_PPRXI))
+ max_count += velocity_rx_srv(vptr, isr_status);
+ if (isr_status & (ISR_PTXI | ISR_PPTXI))
+ max_count += velocity_tx_srv(vptr, isr_status);
+ isr_status = mac_read_isr(vptr->mac_regs);
+ if (max_count > vptr->options.int_works) {
+ printk(KERN_WARNING "%s: excessive work at interrupt.\n",
+ dev->name);
+ max_count = 0;
}
}
- dev_kfree_skb_irq(skb);
- tdinfo->skb = NULL;
-}
-
-static int velocity_init_rings(struct velocity_info *vptr, int mtu)
-{
- int ret;
-
- velocity_set_rxbufsize(vptr, mtu);
-
- ret = velocity_init_dma_rings(vptr);
- if (ret < 0)
- goto out;
-
- ret = velocity_init_rd_ring(vptr);
- if (ret < 0)
- goto err_free_dma_rings_0;
-
- ret = velocity_init_td_ring(vptr);
- if (ret < 0)
- goto err_free_rd_ring_1;
-out:
- return ret;
-
-err_free_rd_ring_1:
- velocity_free_rd_ring(vptr);
-err_free_dma_rings_0:
- velocity_free_dma_rings(vptr);
- goto out;
-}
+ spin_unlock(&vptr->lock);
+ mac_enable_int(vptr->mac_regs);
+ return IRQ_HANDLED;
-static void velocity_free_rings(struct velocity_info *vptr)
-{
- velocity_free_td_ring(vptr);
- velocity_free_rd_ring(vptr);
- velocity_free_dma_rings(vptr);
}
/**
@@ -1905,7 +2174,6 @@ static void velocity_free_rings(struct velocity_info *vptr)
* All the ring allocation and set up is done on open for this
* adapter to minimise memory usage when inactive
*/
-
static int velocity_open(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -1939,6 +2207,24 @@ out:
}
/**
+ * velocity_shutdown - shut down the chip
+ * @vptr: velocity to deactivate
+ *
+ * Shuts down the internal operations of the velocity and
+ * disables interrupts, autopolling, transmit and receive
+ */
+static void velocity_shutdown(struct velocity_info *vptr)
+{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ mac_disable_int(regs);
+ writel(CR0_STOP, &regs->CR0Set);
+ writew(0xFFFF, &regs->TDCSRClr);
+ writeb(0xFF, &regs->RDCSRClr);
+ safe_disable_mii_autopoll(regs);
+ mac_clear_isr(regs);
+}
+
+/**
* velocity_change_mtu - MTU change callback
* @dev: network device
* @new_mtu: desired MTU
@@ -1947,7 +2233,6 @@ out:
* this interface. It gets called on a change by the network layer.
* Return zero for success or negative posix error code.
*/
-
static int velocity_change_mtu(struct net_device *dev, int new_mtu)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2021,22 +2306,127 @@ out_0:
}
/**
- * velocity_shutdown - shut down the chip
- * @vptr: velocity to deactivate
+ * velocity_mii_ioctl - MII ioctl handler
+ * @dev: network device
+ * @ifr: the ifreq block for the ioctl
+ * @cmd: the command
*
- * Shuts down the internal operations of the velocity and
- * disables interrupts, autopolling, transmit and receive
+ * Process MII requests made via ioctl from the network layer. These
+ * are used by tools like kudzu to interrogate the link state of the
+ * hardware
*/
+static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ unsigned long flags;
+ struct mii_ioctl_data *miidata = if_mii(ifr);
+ int err;
-static void velocity_shutdown(struct velocity_info *vptr)
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
+ break;
+ case SIOCGMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
+ return -ETIMEDOUT;
+ break;
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ spin_lock_irqsave(&vptr->lock, flags);
+ err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ check_connection_type(vptr->mac_regs);
+ if (err)
+ return err;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+
+/**
+ * velocity_ioctl - ioctl entry point
+ * @dev: network device
+ * @rq: interface request ioctl
+ * @cmd: command code
+ *
+ * Called when the user issues an ioctl request to the network
+ * device in question. The velocity interface supports MII.
+ */
+static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- mac_disable_int(regs);
- writel(CR0_STOP, &regs->CR0Set);
- writew(0xFFFF, &regs->TDCSRClr);
- writeb(0xFF, &regs->RDCSRClr);
- safe_disable_mii_autopoll(regs);
- mac_clear_isr(regs);
+ struct velocity_info *vptr = netdev_priv(dev);
+ int ret;
+
+ /* If we are asked for information and the device is power
+ 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);
+
+ switch (cmd) {
+ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
+ case SIOCGMIIREG: /* Read MII PHY register. */
+ case SIOCSMIIREG: /* Write to MII PHY register. */
+ ret = velocity_mii_ioctl(dev, rq, cmd);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+ if (!netif_running(dev))
+ pci_set_power_state(vptr->pdev, PCI_D3hot);
+
+
+ return ret;
+}
+
+/**
+ * velocity_get_status - statistics callback
+ * @dev: network device
+ *
+ * Callback from the network layer to allow driver statistics
+ * to be resynchronized with hardware collected state. In the
+ * case of the velocity we need to pull the MIB counters from
+ * the hardware into the counters before letting the network
+ * layer display them.
+ */
+static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+{
+ struct velocity_info *vptr = netdev_priv(dev);
+
+ /* If the hardware is down, don't touch MII */
+ if (!netif_running(dev))
+ return &dev->stats;
+
+ spin_lock_irq(&vptr->lock);
+ velocity_update_hw_mibs(vptr);
+ spin_unlock_irq(&vptr->lock);
+
+ dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
+ dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
+ dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
+
+// unsigned long rx_dropped; /* no space in linux buffers */
+ dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
+ /* detailed rx_errors: */
+// unsigned long rx_length_errors;
+// unsigned long rx_over_errors; /* receiver ring buff overflow */
+ dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
+// unsigned long rx_frame_errors; /* recv'd frame alignment error */
+// unsigned long rx_fifo_errors; /* recv'r fifo overrun */
+// unsigned long rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+// unsigned long tx_fifo_errors;
+
+ return &dev->stats;
}
/**
@@ -2046,7 +2436,6 @@ static void velocity_shutdown(struct velocity_info *vptr)
* Callback from the network layer when the velocity is being
* deactivated by the network layer
*/
-
static int velocity_close(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2076,7 +2465,6 @@ static int velocity_close(struct net_device *dev)
* Called by the networ layer to request a packet is queued to
* the velocity. Returns zero on success.
*/
-
static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -2088,20 +2476,12 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
__le16 len;
int index;
-
if (skb_padto(skb, ETH_ZLEN))
goto out;
pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
len = cpu_to_le16(pktlen);
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
- kfree_skb(skb);
- return 0;
- }
-#endif
-
spin_lock_irqsave(&vptr->lock, flags);
index = vptr->tx.curr[qnum];
@@ -2111,59 +2491,18 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
td_ptr->tdesc1.TCR = TCR0_TIC;
td_ptr->td_buf[0].size &= ~TD_QUEUE;
-#ifdef VELOCITY_ZERO_COPY_SUPPORT
- if (skb_shinfo(skb)->nr_frags > 0) {
- int nfrags = skb_shinfo(skb)->nr_frags;
- tdinfo->skb = skb;
- if (nfrags > 6) {
- skb_copy_from_linear_data(skb, tdinfo->buf, skb->len);
- tdinfo->skb_dma[0] = tdinfo->buf_dma;
- td_ptr->tdesc0.len = len;
- td_ptr->tx.buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
- td_ptr->tx.buf[0].pa_high = 0;
- td_ptr->tx.buf[0].size = len; /* queue is 0 anyway */
- tdinfo->nskb_dma = 1;
- } else {
- int i = 0;
- tdinfo->nskb_dma = 0;
- tdinfo->skb_dma[i] = pci_map_single(vptr->pdev, skb->data,
- skb_headlen(skb), PCI_DMA_TODEVICE);
-
- td_ptr->tdesc0.len = len;
-
- /* FIXME: support 48bit DMA later */
- td_ptr->tx.buf[i].pa_low = cpu_to_le32(tdinfo->skb_dma);
- td_ptr->tx.buf[i].pa_high = 0;
- td_ptr->tx.buf[i].size = cpu_to_le16(skb_headlen(skb));
-
- for (i = 0; i < nfrags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- void *addr = (void *)page_address(frag->page) + frag->page_offset;
-
- tdinfo->skb_dma[i + 1] = pci_map_single(vptr->pdev, addr, frag->size, PCI_DMA_TODEVICE);
-
- td_ptr->tx.buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]);
- td_ptr->tx.buf[i + 1].pa_high = 0;
- td_ptr->tx.buf[i + 1].size = cpu_to_le16(frag->size);
- }
- tdinfo->nskb_dma = i - 1;
- }
+ /*
+ * Map the linear network buffer into PCI space and
+ * add it to the transmit ring.
+ */
+ tdinfo->skb = skb;
+ tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
+ td_ptr->tdesc0.len = len;
+ td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
+ td_ptr->td_buf[0].pa_high = 0;
+ td_ptr->td_buf[0].size = len;
+ tdinfo->nskb_dma = 1;
- } else
-#endif
- {
- /*
- * Map the linear network buffer into PCI space and
- * add it to the transmit ring.
- */
- tdinfo->skb = skb;
- tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE);
- td_ptr->tdesc0.len = len;
- td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
- td_ptr->td_buf[0].pa_high = 0;
- td_ptr->td_buf[0].size = len;
- tdinfo->nskb_dma = 1;
- }
td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
@@ -2206,782 +2545,533 @@ out:
return NETDEV_TX_OK;
}
+
+static const struct net_device_ops velocity_netdev_ops = {
+ .ndo_open = velocity_open,
+ .ndo_stop = velocity_close,
+ .ndo_start_xmit = velocity_xmit,
+ .ndo_get_stats = velocity_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_multicast_list = velocity_set_multi,
+ .ndo_change_mtu = velocity_change_mtu,
+ .ndo_do_ioctl = velocity_ioctl,
+ .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid,
+ .ndo_vlan_rx_register = velocity_vlan_rx_register,
+};
+
/**
- * velocity_intr - interrupt callback
- * @irq: interrupt number
- * @dev_instance: interrupting device
+ * velocity_init_info - init private data
+ * @pdev: PCI device
+ * @vptr: Velocity info
+ * @info: Board type
*
- * Called whenever an interrupt is generated by the velocity
- * adapter IRQ line. We may not be the source of the interrupt
- * and need to identify initially if we are, and if not exit as
- * efficiently as possible.
+ * Set up the initial velocity_info struct for the device that has been
+ * discovered.
*/
-
-static irqreturn_t velocity_intr(int irq, void *dev_instance)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+ struct velocity_info *vptr,
+ const struct velocity_info_tbl *info)
{
- struct net_device *dev = dev_instance;
- struct velocity_info *vptr = netdev_priv(dev);
- u32 isr_status;
- int max_count = 0;
-
-
- spin_lock(&vptr->lock);
- isr_status = mac_read_isr(vptr->mac_regs);
-
- /* Not us ? */
- if (isr_status == 0) {
- spin_unlock(&vptr->lock);
- return IRQ_NONE;
- }
-
- mac_disable_int(vptr->mac_regs);
-
- /*
- * Keep processing the ISR until we have completed
- * processing and the isr_status becomes zero
- */
-
- while (isr_status != 0) {
- mac_write_isr(vptr->mac_regs, isr_status);
- if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
- velocity_error(vptr, isr_status);
- if (isr_status & (ISR_PRXI | ISR_PPRXI))
- max_count += velocity_rx_srv(vptr, isr_status);
- if (isr_status & (ISR_PTXI | ISR_PPTXI))
- max_count += velocity_tx_srv(vptr, isr_status);
- isr_status = mac_read_isr(vptr->mac_regs);
- if (max_count > vptr->options.int_works)
- {
- printk(KERN_WARNING "%s: excessive work at interrupt.\n",
- dev->name);
- max_count = 0;
- }
- }
- spin_unlock(&vptr->lock);
- mac_enable_int(vptr->mac_regs);
- return IRQ_HANDLED;
+ 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;
+ spin_lock_init(&vptr->lock);
+ INIT_LIST_HEAD(&vptr->list);
}
-
/**
- * velocity_set_multi - filter list change callback
- * @dev: network device
+ * velocity_get_pci_info - retrieve PCI info for device
+ * @vptr: velocity device
+ * @pdev: PCI device it matches
*
- * Called by the network layer when the filter lists need to change
- * for a velocity adapter. Reload the CAMs with the new address
- * filter ruleset.
+ * Retrieve the PCI configuration space data that interests us from
+ * the kernel PCI layer
*/
-
-static void velocity_set_multi(struct net_device *dev)
+static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
- u8 rx_mode;
- int i;
- struct dev_mc_list *mclist;
+ vptr->rev_id = pdev->revision;
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- writel(0xffffffff, &regs->MARCAM[0]);
- writel(0xffffffff, &regs->MARCAM[4]);
- rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
- } else if ((dev->mc_count > vptr->multicast_limit)
- || (dev->flags & IFF_ALLMULTI)) {
- writel(0xffffffff, &regs->MARCAM[0]);
- writel(0xffffffff, &regs->MARCAM[4]);
- rx_mode = (RCR_AM | RCR_AB);
- } else {
- int offset = MCAM_SIZE - vptr->multicast_limit;
- mac_get_cam_mask(regs, vptr->mCAMmask);
+ pci_set_master(pdev);
- for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
- mac_set_cam(regs, i + offset, mclist->dmi_addr);
- vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
- }
+ vptr->ioaddr = pci_resource_start(pdev, 0);
+ vptr->memaddr = pci_resource_start(pdev, 1);
- mac_set_cam_mask(regs, vptr->mCAMmask);
- rx_mode = RCR_AM | RCR_AB | RCR_AP;
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #0 is not an I/O resource, aborting.\n");
+ return -EINVAL;
}
- if (dev->mtu > 1500)
- rx_mode |= RCR_AL;
- BYTE_REG_BITS_ON(rx_mode, &regs->RCR);
+ if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #1 is an I/O resource, aborting.\n");
+ return -EINVAL;
+ }
+ if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+ dev_err(&pdev->dev, "region #1 is too small.\n");
+ return -EINVAL;
+ }
+ vptr->pdev = pdev;
+
+ return 0;
}
/**
- * velocity_get_status - statistics callback
- * @dev: network device
+ * velocity_print_info - per driver data
+ * @vptr: velocity
*
- * Callback from the network layer to allow driver statistics
- * to be resynchronized with hardware collected state. In the
- * case of the velocity we need to pull the MIB counters from
- * the hardware into the counters before letting the network
- * layer display them.
+ * Print per driver data as the kernel driver finds Velocity
+ * hardware
*/
-
-static struct net_device_stats *velocity_get_stats(struct net_device *dev)
+static void __devinit velocity_print_info(struct velocity_info *vptr)
{
- struct velocity_info *vptr = netdev_priv(dev);
-
- /* If the hardware is down, don't touch MII */
- if(!netif_running(dev))
- return &dev->stats;
-
- spin_lock_irq(&vptr->lock);
- velocity_update_hw_mibs(vptr);
- spin_unlock_irq(&vptr->lock);
-
- dev->stats.rx_packets = vptr->mib_counter[HW_MIB_ifRxAllPkts];
- dev->stats.rx_errors = vptr->mib_counter[HW_MIB_ifRxErrorPkts];
- dev->stats.rx_length_errors = vptr->mib_counter[HW_MIB_ifInRangeLengthErrors];
-
-// unsigned long rx_dropped; /* no space in linux buffers */
- dev->stats.collisions = vptr->mib_counter[HW_MIB_ifTxEtherCollisions];
- /* detailed rx_errors: */
-// unsigned long rx_length_errors;
-// unsigned long rx_over_errors; /* receiver ring buff overflow */
- dev->stats.rx_crc_errors = vptr->mib_counter[HW_MIB_ifRxPktCRCE];
-// unsigned long rx_frame_errors; /* recv'd frame alignment error */
-// unsigned long rx_fifo_errors; /* recv'r fifo overrun */
-// unsigned long rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
-// unsigned long tx_fifo_errors;
+ struct net_device *dev = vptr->dev;
- return &dev->stats;
+ printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
+ printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+ dev->name,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
}
-
-/**
- * velocity_ioctl - ioctl entry point
- * @dev: network device
- * @rq: interface request ioctl
- * @cmd: command code
- *
- * Called when the user issues an ioctl request to the network
- * device in question. The velocity interface supports MII.
- */
-
-static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+static u32 velocity_get_link(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
- int ret;
-
- /* If we are asked for information and the device is power
- 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);
-
- switch (cmd) {
- case SIOCGMIIPHY: /* Get address of MII PHY in use. */
- case SIOCGMIIREG: /* Read MII PHY register. */
- case SIOCSMIIREG: /* Write to MII PHY register. */
- ret = velocity_mii_ioctl(dev, rq, cmd);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
- if (!netif_running(dev))
- pci_set_power_state(vptr->pdev, PCI_D3hot);
-
-
- return ret;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
}
-/*
- * 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 = {
- .name = VELOCITY_NAME,
- .id_table = velocity_id_table,
- .probe = velocity_found1,
- .remove = __devexit_p(velocity_remove1),
-#ifdef CONFIG_PM
- .suspend = velocity_suspend,
- .resume = velocity_resume,
-#endif
-};
/**
- * velocity_init_module - load time function
+ * velocity_found1 - set up discovered velocity card
+ * @pdev: PCI device
+ * @ent: PCI device table entry that matched
*
- * Called when the velocity module is loaded. The PCI driver
- * is registered with the PCI layer, and in turn will call
- * the probe functions for each velocity adapter installed
- * in the system.
+ * Configure a discovered adapter from scratch. Return a negative
+ * errno error code on failure paths.
*/
-
-static int __init velocity_init_module(void)
+static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- int ret;
+ static int first = 1;
+ struct net_device *dev;
+ 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;
- velocity_register_notifier();
- ret = pci_register_driver(&velocity_driver);
- if (ret < 0)
- velocity_unregister_notifier();
- return ret;
-}
+ /* FIXME: this driver, like almost all other ethernet drivers,
+ * can support more than MAX_UNITS.
+ */
+ if (velocity_nics >= MAX_UNITS) {
+ dev_notice(&pdev->dev, "already found %d NICs.\n",
+ velocity_nics);
+ return -ENODEV;
+ }
-/**
- * velocity_cleanup - module unload
- *
- * When the velocity hardware is unloaded this function is called.
- * It will clean up the notifiers and the unregister the PCI
- * driver interface for this hardware. This in turn cleans up
- * all discovered interfaces before returning from the function
- */
+ dev = alloc_etherdev(sizeof(struct velocity_info));
+ if (!dev) {
+ dev_err(&pdev->dev, "allocate net device failed.\n");
+ goto out;
+ }
-static void __exit velocity_cleanup_module(void)
-{
- velocity_unregister_notifier();
- pci_unregister_driver(&velocity_driver);
-}
+ /* Chain it all together */
-module_init(velocity_init_module);
-module_exit(velocity_cleanup_module);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ vptr = netdev_priv(dev);
-/*
- * MII access , media link mode setting functions
- */
+ if (first) {
+ printk(KERN_INFO "%s Ver. %s\n",
+ VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
+ printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
+ printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
+ first = 0;
+ }
+ velocity_init_info(pdev, vptr, info);
-/**
- * mii_init - set up MII
- * @vptr: velocity adapter
- * @mii_status: links tatus
- *
- * Set up the PHY for the current link state.
- */
+ vptr->dev = dev;
-static void mii_init(struct velocity_info *vptr, u32 mii_status)
-{
- u16 BMCR;
+ dev->irq = pdev->irq;
- switch (PHYID_GET_PHY_ID(vptr->phy_id)) {
- case PHYID_CICADA_CS8201:
- /*
- * Reset to hardware default
- */
- MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
- /*
- * Turn on ECHODIS bit in NWay-forced full mode and turn it
- * off it in NWay-forced half mode for NWay-forced v.s.
- * legacy-forced issue.
- */
- if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
- MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- else
- MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- /*
- * Turn on Link/Activity LED enable bit for CIS8201
- */
- MII_REG_BITS_ON(PLED_LALBE, MII_REG_PLED, vptr->mac_regs);
- break;
- case PHYID_VT3216_32BIT:
- case PHYID_VT3216_64BIT:
- /*
- * Reset to hardware default
- */
- MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
- /*
- * Turn on ECHODIS bit in NWay-forced full mode and turn it
- * off it in NWay-forced half mode for NWay-forced v.s.
- * legacy-forced issue
- */
- if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
- MII_REG_BITS_ON(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- else
- MII_REG_BITS_OFF(TCSR_ECHODIS, MII_REG_TCSR, vptr->mac_regs);
- break;
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ goto err_free_dev;
- case PHYID_MARVELL_1000:
- case PHYID_MARVELL_1000S:
- /*
- * Assert CRS on Transmit
- */
- MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
- /*
- * Reset to hardware default
- */
- MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
- break;
- default:
- ;
- }
- velocity_mii_read(vptr->mac_regs, MII_REG_BMCR, &BMCR);
- if (BMCR & BMCR_ISO) {
- BMCR &= ~BMCR_ISO;
- velocity_mii_write(vptr->mac_regs, MII_REG_BMCR, BMCR);
+ ret = velocity_get_pci_info(vptr, pdev);
+ if (ret < 0) {
+ /* error message already printed */
+ goto err_disable;
}
-}
-/**
- * safe_disable_mii_autopoll - autopoll off
- * @regs: velocity registers
- *
- * Turn off the autopoll and wait for it to disable on the chip
- */
-
-static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
-{
- u16 ww;
-
- /* turn off MAUTO */
- writeb(0, &regs->MIICR);
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- udelay(1);
- if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
+ ret = pci_request_regions(pdev, VELOCITY_NAME);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "No PCI resources.\n");
+ goto err_disable;
}
-}
-
-/**
- * enable_mii_autopoll - turn on autopolling
- * @regs: velocity registers
- *
- * Enable the MII link status autopoll feature on the Velocity
- * hardware. Wait for it to enable.
- */
-static void enable_mii_autopoll(struct mac_regs __iomem * regs)
-{
- int ii;
+ regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
+ if (regs == NULL) {
+ ret = -EIO;
+ goto err_release_res;
+ }
- writeb(0, &(regs->MIICR));
- writeb(MIIADR_SWMPL, &regs->MIIADR);
+ vptr->mac_regs = regs;
- for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
- udelay(1);
- if (BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
- }
+ mac_wol_reset(regs);
- writeb(MIICR_MAUTO, &regs->MIICR);
+ dev->base_addr = vptr->ioaddr;
- for (ii = 0; ii < W_MAX_TIMEOUT; ii++) {
- udelay(1);
- if (!BYTE_REG_BITS_IS_ON(MIISR_MIDLE, &regs->MIISR))
- break;
- }
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = readb(&regs->PAR[i]);
-}
-/**
- * velocity_mii_read - read MII data
- * @regs: velocity registers
- * @index: MII register index
- * @data: buffer for received data
- *
- * Perform a single read of an MII 16bit register. Returns zero
- * on success or -ETIMEDOUT if the PHY did not respond.
- */
+ drv_string = dev_driver_string(&pdev->dev);
-static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
-{
- u16 ww;
+ velocity_get_options(&vptr->options, velocity_nics, drv_string);
/*
- * Disable MIICR_MAUTO, so that mii addr can be set normally
+ * Mask out the options cannot be set to the chip
*/
- safe_disable_mii_autopoll(regs);
-
- writeb(index, &regs->MIIADR);
- BYTE_REG_BITS_ON(MIICR_RCMD, &regs->MIICR);
+ vptr->options.flags &= info->flags;
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- if (!(readb(&regs->MIICR) & MIICR_RCMD))
- break;
- }
+ /*
+ * Enable the chip specified capbilities
+ */
- *data = readw(&regs->MIIDATA);
+ vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
- enable_mii_autopoll(regs);
- if (ww == W_MAX_TIMEOUT)
- return -ETIMEDOUT;
- return 0;
-}
+ vptr->wol_opts = vptr->options.wol_opts;
+ vptr->flags |= VELOCITY_FLAGS_WOL_ENABLED;
-/**
- * velocity_mii_write - write MII data
- * @regs: velocity registers
- * @index: MII register index
- * @data: 16bit data for the MII register
- *
- * Perform a single write to an MII 16bit register. Returns zero
- * on success or -ETIMEDOUT if the PHY did not respond.
- */
+ vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs);
-static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
-{
- u16 ww;
+ dev->irq = pdev->irq;
+ dev->netdev_ops = &velocity_netdev_ops;
+ dev->ethtool_ops = &velocity_ethtool_ops;
- /*
- * Disable MIICR_MAUTO, so that mii addr can be set normally
- */
- safe_disable_mii_autopoll(regs);
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
+ NETIF_F_HW_VLAN_RX;
- /* MII reg offset */
- writeb(mii_addr, &regs->MIIADR);
- /* set MII data */
- writew(data, &regs->MIIDATA);
+ if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
+ dev->features |= NETIF_F_IP_CSUM;
- /* turn on MIICR_WCMD */
- BYTE_REG_BITS_ON(MIICR_WCMD, &regs->MIICR);
+ ret = register_netdev(dev);
+ if (ret < 0)
+ goto err_iounmap;
- /* W_MAX_TIMEOUT is the timeout period */
- for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- udelay(5);
- if (!(readb(&regs->MIICR) & MIICR_WCMD))
- break;
+ if (!velocity_get_link(dev)) {
+ netif_carrier_off(dev);
+ vptr->mii_status |= VELOCITY_LINK_FAIL;
}
- enable_mii_autopoll(regs);
- if (ww == W_MAX_TIMEOUT)
- return -ETIMEDOUT;
- return 0;
-}
+ velocity_print_info(vptr);
+ pci_set_drvdata(pdev, dev);
-/**
- * velocity_get_opt_media_mode - get media selection
- * @vptr: velocity adapter
- *
- * Get the media mode stored in EEPROM or module options and load
- * mii_status accordingly. The requested link state information
- * is also returned.
- */
+ /* and leave the chip powered down */
-static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
-{
- u32 status = 0;
+ pci_set_power_state(pdev, PCI_D3hot);
+#ifdef CONFIG_PM
+ {
+ unsigned long flags;
- switch (vptr->options.spd_dpx) {
- case SPD_DPX_AUTO:
- status = VELOCITY_AUTONEG_ENABLE;
- break;
- case SPD_DPX_100_FULL:
- status = VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL;
- break;
- case SPD_DPX_10_FULL:
- status = VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL;
- break;
- case SPD_DPX_100_HALF:
- status = VELOCITY_SPEED_100;
- break;
- case SPD_DPX_10_HALF:
- status = VELOCITY_SPEED_10;
- break;
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_add(&vptr->list, &velocity_dev_list);
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
}
- vptr->mii_status = status;
- return status;
-}
-
-/**
- * mii_set_auto_on - autonegotiate on
- * @vptr: velocity
- *
- * Enable autonegotation on this interface
- */
+#endif
+ velocity_nics++;
+out:
+ return ret;
-static void mii_set_auto_on(struct velocity_info *vptr)
-{
- if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
- MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
- else
- MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
+err_iounmap:
+ iounmap(regs);
+err_release_res:
+ pci_release_regions(pdev);
+err_disable:
+ pci_disable_device(pdev);
+err_free_dev:
+ free_netdev(dev);
+ goto out;
}
-/*
-static void mii_set_auto_off(struct velocity_info * vptr)
-{
- MII_REG_BITS_OFF(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs);
-}
-*/
-
+#ifdef CONFIG_PM
/**
- * set_mii_flow_control - flow control setup
- * @vptr: velocity interface
+ * wol_calc_crc - WOL CRC
+ * @pattern: data pattern
+ * @mask_pattern: mask
*
- * Set up the flow control on this interface according to
- * the supplied user/eeprom options.
+ * Compute the wake on lan crc hashes for the packet header
+ * we are interested in.
*/
-
-static void set_mii_flow_control(struct velocity_info *vptr)
+static u16 wol_calc_crc(int size, u8 *pattern, u8 *mask_pattern)
{
- /*Enable or Disable PAUSE in ANAR */
- switch (vptr->options.flow_cntl) {
- case FLOW_CNTL_TX:
- MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
- break;
+ u16 crc = 0xFFFF;
+ u8 mask;
+ int i, j;
- case FLOW_CNTL_RX:
- MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
- break;
+ for (i = 0; i < size; i++) {
+ mask = mask_pattern[i];
- case FLOW_CNTL_TX_RX:
- MII_REG_BITS_ON(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_ON(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
- break;
+ /* Skip this loop if the mask equals to zero */
+ if (mask == 0x00)
+ continue;
- case FLOW_CNTL_DISABLE:
- MII_REG_BITS_OFF(ANAR_PAUSE, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_OFF(ANAR_ASMDIR, MII_REG_ANAR, vptr->mac_regs);
- break;
- default:
- break;
+ for (j = 0; j < 8; j++) {
+ if ((mask & 0x01) == 0) {
+ mask >>= 1;
+ continue;
+ }
+ mask >>= 1;
+ crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
+ }
}
+ /* Finally, invert the result once to get the correct data */
+ crc = ~crc;
+ return bitrev32(crc) >> 16;
}
/**
- * velocity_set_media_mode - set media mode
- * @mii_status: old MII link state
+ * velocity_set_wol - set up for wake on lan
+ * @vptr: velocity to set WOL status on
*
- * Check the media link state and configure the flow control
- * PHY and also velocity hardware setup accordingly. In particular
- * we need to set up CD polling and frame bursting.
+ * Set a card up for wake on lan either by unicast or by
+ * ARP packet.
+ *
+ * FIXME: check static buffer is safe here
*/
-
-static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
+static int velocity_set_wol(struct velocity_info *vptr)
{
- u32 curr_status;
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ static u8 buf[256];
+ int i;
- vptr->mii_status = mii_check_media_mode(vptr->mac_regs);
- curr_status = vptr->mii_status & (~VELOCITY_LINK_FAIL);
+ static u32 mask_pattern[2][4] = {
+ {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
+ {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */
+ };
- /* Set mii link status */
- set_mii_flow_control(vptr);
+ writew(0xFFFF, &regs->WOLCRClr);
+ writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
+ writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
/*
- Check if new status is consisent with current status
- if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE)
- || (mii_status==curr_status)) {
- vptr->mii_status=mii_check_media_mode(vptr->mac_regs);
- vptr->mii_status=check_connection_type(vptr->mac_regs);
- VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n");
- return 0;
- }
+ if (vptr->wol_opts & VELOCITY_WOL_PHY)
+ writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
*/
- if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201) {
- MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
- }
+ if (vptr->wol_opts & VELOCITY_WOL_UCAST)
+ writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
- /*
- * If connection type is AUTO
- */
- if (mii_status & VELOCITY_AUTONEG_ENABLE) {
- VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity is AUTO mode\n");
- /* clear force MAC mode bit */
- BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
- /* set duplex mode of MAC according to duplex mode of MII */
- MII_REG_BITS_ON(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10, MII_REG_ANAR, vptr->mac_regs);
- MII_REG_BITS_ON(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
- MII_REG_BITS_ON(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs);
+ if (vptr->wol_opts & VELOCITY_WOL_ARP) {
+ struct arp_packet *arp = (struct arp_packet *) buf;
+ u16 crc;
+ memset(buf, 0, sizeof(struct arp_packet) + 7);
- /* enable AUTO-NEGO mode */
- mii_set_auto_on(vptr);
- } else {
- u16 ANAR;
- u8 CHIPGCR;
+ for (i = 0; i < 4; i++)
+ writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
- /*
- * 1. if it's 3119, disable frame bursting in halfduplex mode
- * and enable it in fullduplex mode
- * 2. set correct MII/GMII and half/full duplex mode in CHIPGCR
- * 3. only enable CD heart beat counter in 10HD mode
- */
+ arp->type = htons(ETH_P_ARP);
+ arp->ar_op = htons(1);
- /* set force MAC mode bit */
- BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+ memcpy(arp->ar_tip, vptr->ip_addr, 4);
- CHIPGCR = readb(&regs->CHIPGCR);
- CHIPGCR &= ~CHIPGCR_FCGMII;
+ crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
+ (u8 *) & mask_pattern[0][0]);
- if (mii_status & VELOCITY_DUPLEX_FULL) {
- CHIPGCR |= CHIPGCR_FCFDX;
- writeb(CHIPGCR, &regs->CHIPGCR);
- VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced full mode\n");
- if (vptr->rev_id < REV_ID_VT3216_A0)
- BYTE_REG_BITS_OFF(TCR_TB2BDIS, &regs->TCR);
- } else {
- CHIPGCR &= ~CHIPGCR_FCFDX;
- VELOCITY_PRT(MSG_LEVEL_INFO, "set Velocity to forced half mode\n");
- writeb(CHIPGCR, &regs->CHIPGCR);
- if (vptr->rev_id < REV_ID_VT3216_A0)
- BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
- }
+ writew(crc, &regs->PatternCRC[0]);
+ writew(WOLCR_ARP_EN, &regs->WOLCRSet);
+ }
+
+ BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
+ BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
+
+ writew(0x0FFF, &regs->WOLSRClr);
+
+ if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
+ if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
+ MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
+ }
- if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10)) {
- BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
- } else {
- BYTE_REG_BITS_ON(TESTCFG_HBDIS, &regs->TESTCFG);
- }
- /* MII_REG_BITS_OFF(BMCR_SPEED1G, MII_REG_BMCR, vptr->mac_regs); */
- velocity_mii_read(vptr->mac_regs, MII_REG_ANAR, &ANAR);
- ANAR &= (~(ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10));
- if (mii_status & VELOCITY_SPEED_100) {
- if (mii_status & VELOCITY_DUPLEX_FULL)
- ANAR |= ANAR_TXFD;
- else
- ANAR |= ANAR_TX;
- } else {
- if (mii_status & VELOCITY_DUPLEX_FULL)
- ANAR |= ANAR_10FD;
- else
- ANAR |= ANAR_10;
- }
- velocity_mii_write(vptr->mac_regs, MII_REG_ANAR, ANAR);
- /* enable AUTO-NEGO mode */
- mii_set_auto_on(vptr);
- /* MII_REG_BITS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs); */
+ if (vptr->mii_status & VELOCITY_SPEED_1000)
+ MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
+
+ BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
+
+ {
+ u8 GCR;
+ GCR = readb(&regs->CHIPGCR);
+ GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
+ writeb(GCR, &regs->CHIPGCR);
}
- /* vptr->mii_status=mii_check_media_mode(vptr->mac_regs); */
- /* vptr->mii_status=check_connection_type(vptr->mac_regs); */
- return VELOCITY_LINK_CHANGE;
+
+ BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
+ /* Turn on SWPTAG just before entering power mode */
+ BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
+ /* Go to bed ..... */
+ BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+ return 0;
}
/**
- * mii_check_media_mode - check media state
- * @regs: velocity registers
+ * velocity_save_context - save registers
+ * @vptr: velocity
+ * @context: buffer for stored context
*
- * Check the current MII status and determine the link status
- * accordingly
+ * Retrieve the current configuration from the velocity hardware
+ * and stash it in the context structure, for use by the context
+ * restore functions. This allows us to save things we need across
+ * power down states
*/
-
-static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
+static void velocity_save_context(struct velocity_info *vptr, struct velocity_context *context)
{
- u32 status = 0;
- u16 ANAR;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ u16 i;
+ u8 __iomem *ptr = (u8 __iomem *)regs;
- if (!MII_REG_BITS_IS_ON(BMSR_LNK, MII_REG_BMSR, regs))
- status |= VELOCITY_LINK_FAIL;
+ for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- if (MII_REG_BITS_IS_ON(G1000CR_1000FD, MII_REG_G1000CR, regs))
- status |= VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
- else if (MII_REG_BITS_IS_ON(G1000CR_1000, MII_REG_G1000CR, regs))
- status |= (VELOCITY_SPEED_1000);
- else {
- velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
- if (ANAR & ANAR_TXFD)
- status |= (VELOCITY_SPEED_100 | VELOCITY_DUPLEX_FULL);
- else if (ANAR & ANAR_TX)
- status |= VELOCITY_SPEED_100;
- else if (ANAR & ANAR_10FD)
- status |= (VELOCITY_SPEED_10 | VELOCITY_DUPLEX_FULL);
- else
- status |= (VELOCITY_SPEED_10);
- }
+ for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
- velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
- if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
- == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
- if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
- status |= VELOCITY_AUTONEG_ENABLE;
- }
- }
+ for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+ *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
- return status;
}
-static u32 check_connection_type(struct mac_regs __iomem * regs)
+static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
{
- u32 status = 0;
- u8 PHYSR0;
- u16 ANAR;
- PHYSR0 = readb(&regs->PHYSR0);
-
- /*
- if (!(PHYSR0 & PHYSR0_LINKGD))
- status|=VELOCITY_LINK_FAIL;
- */
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct velocity_info *vptr = netdev_priv(dev);
+ unsigned long flags;
- if (PHYSR0 & PHYSR0_FDPX)
- status |= VELOCITY_DUPLEX_FULL;
+ if (!netif_running(vptr->dev))
+ return 0;
- if (PHYSR0 & PHYSR0_SPDG)
- status |= VELOCITY_SPEED_1000;
- else if (PHYSR0 & PHYSR0_SPD10)
- status |= VELOCITY_SPEED_10;
- else
- status |= VELOCITY_SPEED_100;
+ netif_device_detach(vptr->dev);
- if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, regs)) {
- velocity_mii_read(regs, MII_REG_ANAR, &ANAR);
- if ((ANAR & (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10))
- == (ANAR_TXFD | ANAR_TX | ANAR_10FD | ANAR_10)) {
- if (MII_REG_BITS_IS_ON(G1000CR_1000 | G1000CR_1000FD, MII_REG_G1000CR, regs))
- status |= VELOCITY_AUTONEG_ENABLE;
- }
+ spin_lock_irqsave(&vptr->lock, flags);
+ pci_save_state(pdev);
+#ifdef ETHTOOL_GWOL
+ 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);
+ } else {
+ velocity_save_context(vptr, &vptr->context);
+ velocity_shutdown(vptr);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
-
- return status;
+#else
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+#endif
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ return 0;
}
/**
- * enable_flow_control_ability - flow control
- * @vptr: veloity to configure
+ * velocity_restore_context - restore registers
+ * @vptr: velocity
+ * @context: buffer for stored context
*
- * Set up flow control according to the flow control options
- * determined by the eeprom/configuration.
+ * Reload the register configuration from the velocity context
+ * created by velocity_save_context.
*/
-
-static void enable_flow_control_ability(struct velocity_info *vptr)
+static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
{
+ struct mac_regs __iomem *regs = vptr->mac_regs;
+ int i;
+ u8 __iomem *ptr = (u8 __iomem *)regs;
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- switch (vptr->options.flow_cntl) {
+ /* Just skip cr0 */
+ for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
+ /* Clear */
+ writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
+ /* Set */
+ writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+ }
- case FLOW_CNTL_DEFAULT:
- if (BYTE_REG_BITS_IS_ON(PHYSR0_RXFLC, &regs->PHYSR0))
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- else
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
+ for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- if (BYTE_REG_BITS_IS_ON(PHYSR0_TXFLC, &regs->PHYSR0))
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- else
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+ for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
+ writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- case FLOW_CNTL_TX:
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
- break;
+ for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++)
+ writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
+}
- case FLOW_CNTL_RX:
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+static int velocity_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct velocity_info *vptr = netdev_priv(dev);
+ unsigned long flags;
+ int i;
- case FLOW_CNTL_TX_RX:
- writel(CR0_FDXTFCEN, &regs->CR0Set);
- writel(CR0_FDXRFCEN, &regs->CR0Set);
- break;
+ if (!netif_running(vptr->dev))
+ return 0;
- case FLOW_CNTL_DISABLE:
- writel(CR0_FDXRFCEN, &regs->CR0Clr);
- writel(CR0_FDXTFCEN, &regs->CR0Clr);
- break;
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_wake(pdev, 0, 0);
+ pci_restore_state(pdev);
- default:
- break;
+ mac_wol_reset(vptr->mac_regs);
+
+ spin_lock_irqsave(&vptr->lock, flags);
+ velocity_restore_context(vptr, &vptr->context);
+ velocity_init_registers(vptr, VELOCITY_INIT_WOL);
+ mac_disable_int(vptr->mac_regs);
+
+ velocity_tx_srv(vptr, 0);
+
+ for (i = 0; i < vptr->tx.numq; i++) {
+ if (vptr->tx.used[i])
+ mac_tx_queue_wake(vptr->mac_regs, i);
}
+ mac_enable_int(vptr->mac_regs);
+ spin_unlock_irqrestore(&vptr->lock, flags);
+ netif_device_attach(vptr->dev);
+
+ return 0;
}
+#endif
+
+/*
+ * 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 = {
+ .name = VELOCITY_NAME,
+ .id_table = velocity_id_table,
+ .probe = velocity_found1,
+ .remove = __devexit_p(velocity_remove1),
+#ifdef CONFIG_PM
+ .suspend = velocity_suspend,
+ .resume = velocity_resume,
+#endif
+};
/**
@@ -2991,7 +3081,6 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
* Called before an ethtool operation. We need to make sure the
* chip is out of D3 state before we poke at it.
*/
-
static int velocity_ethtool_up(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3007,7 +3096,6 @@ static int velocity_ethtool_up(struct net_device *dev)
* Called after an ethtool operation. Restore the chip back to D3
* state if it isn't running.
*/
-
static void velocity_ethtool_down(struct net_device *dev)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3018,7 +3106,7 @@ static void velocity_ethtool_down(struct net_device *dev)
static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct mac_regs __iomem *regs = vptr->mac_regs;
u32 status;
status = check_connection_type(vptr->mac_regs);
@@ -3072,13 +3160,6 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
return ret;
}
-static u32 velocity_get_link(struct net_device *dev)
-{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
- return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
-}
-
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct velocity_info *vptr = netdev_priv(dev);
@@ -3157,338 +3238,86 @@ static const struct ethtool_ops velocity_ethtool_ops = {
.complete = velocity_ethtool_down
};
-/**
- * velocity_mii_ioctl - MII ioctl handler
- * @dev: network device
- * @ifr: the ifreq block for the ioctl
- * @cmd: the command
- *
- * Process MII requests made via ioctl from the network layer. These
- * are used by tools like kudzu to interrogate the link state of the
- * hardware
- */
-
-static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+#ifdef CONFIG_PM
+#ifdef CONFIG_INET
+static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
{
- struct velocity_info *vptr = netdev_priv(dev);
- struct mac_regs __iomem * regs = vptr->mac_regs;
+ struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
+ struct net_device *dev = ifa->ifa_dev->dev;
+ struct velocity_info *vptr;
unsigned long flags;
- struct mii_ioctl_data *miidata = if_mii(ifr);
- int err;
- switch (cmd) {
- case SIOCGMIIPHY:
- miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
- break;
- case SIOCGMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if(velocity_mii_read(vptr->mac_regs, miidata->reg_num & 0x1f, &(miidata->val_out)) < 0)
- return -ETIMEDOUT;
- break;
- case SIOCSMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- spin_lock_irqsave(&vptr->lock, flags);
- err = velocity_mii_write(vptr->mac_regs, miidata->reg_num & 0x1f, miidata->val_in);
- spin_unlock_irqrestore(&vptr->lock, flags);
- check_connection_type(vptr->mac_regs);
- if(err)
- return err;
- break;
- default:
- return -EOPNOTSUPP;
+ if (dev_net(dev) != &init_net)
+ return NOTIFY_DONE;
+
+ spin_lock_irqsave(&velocity_dev_list_lock, flags);
+ list_for_each_entry(vptr, &velocity_dev_list, list) {
+ if (vptr->dev == dev) {
+ velocity_get_ip(vptr);
+ break;
+ }
}
- return 0;
-}
+ spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-#ifdef CONFIG_PM
+ return NOTIFY_DONE;
+}
+#endif /* CONFIG_INET */
+#endif /* CONFIG_PM */
-/**
- * velocity_save_context - save registers
- * @vptr: velocity
- * @context: buffer for stored context
- *
- * Retrieve the current configuration from the velocity hardware
- * and stash it in the context structure, for use by the context
- * restore functions. This allows us to save things we need across
- * power down states
- */
+#if defined(CONFIG_PM) && defined(CONFIG_INET)
+static struct notifier_block velocity_inetaddr_notifier = {
+ .notifier_call = velocity_netdev_event,
+};
-static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
+static void velocity_register_notifier(void)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- u16 i;
- u8 __iomem *ptr = (u8 __iomem *)regs;
-
- for (i = MAC_REG_PAR; i < MAC_REG_CR0_CLR; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
- for (i = MAC_REG_MAR; i < MAC_REG_TDCSR_CLR; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
- for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4)
- *((u32 *) (context->mac_reg + i)) = readl(ptr + i);
-
+ register_inetaddr_notifier(&velocity_inetaddr_notifier);
}
-/**
- * velocity_restore_context - restore registers
- * @vptr: velocity
- * @context: buffer for stored context
- *
- * Reload the register configuration from the velocity context
- * created by velocity_save_context.
- */
-
-static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
+static void velocity_unregister_notifier(void)
{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- int i;
- u8 __iomem *ptr = (u8 __iomem *)regs;
-
- for (i = MAC_REG_PAR; i < MAC_REG_CR0_SET; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
-
- /* Just skip cr0 */
- for (i = MAC_REG_CR1_SET; i < MAC_REG_CR0_CLR; i++) {
- /* Clear */
- writeb(~(*((u8 *) (context->mac_reg + i))), ptr + i + 4);
- /* Set */
- writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
- }
-
- for (i = MAC_REG_MAR; i < MAC_REG_IMR; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
+ unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
- for (i = MAC_REG_RDBASE_LO; i < MAC_REG_FIFO_TEST0; i += 4) {
- writel(*((u32 *) (context->mac_reg + i)), ptr + i);
- }
+#else
- for (i = MAC_REG_TDCSR_SET; i <= MAC_REG_RDCSR_SET; i++) {
- writeb(*((u8 *) (context->mac_reg + i)), ptr + i);
- }
+#define velocity_register_notifier() do {} while (0)
+#define velocity_unregister_notifier() do {} while (0)
-}
+#endif /* defined(CONFIG_PM) && defined(CONFIG_INET) */
/**
- * wol_calc_crc - WOL CRC
- * @pattern: data pattern
- * @mask_pattern: mask
+ * velocity_init_module - load time function
*
- * Compute the wake on lan crc hashes for the packet header
- * we are interested in.
+ * Called when the velocity module is loaded. The PCI driver
+ * is registered with the PCI layer, and in turn will call
+ * the probe functions for each velocity adapter installed
+ * in the system.
*/
-
-static u16 wol_calc_crc(int size, u8 * pattern, u8 *mask_pattern)
+static int __init velocity_init_module(void)
{
- u16 crc = 0xFFFF;
- u8 mask;
- int i, j;
-
- for (i = 0; i < size; i++) {
- mask = mask_pattern[i];
-
- /* Skip this loop if the mask equals to zero */
- if (mask == 0x00)
- continue;
+ int ret;
- for (j = 0; j < 8; j++) {
- if ((mask & 0x01) == 0) {
- mask >>= 1;
- continue;
- }
- mask >>= 1;
- crc = crc_ccitt(crc, &(pattern[i * 8 + j]), 1);
- }
- }
- /* Finally, invert the result once to get the correct data */
- crc = ~crc;
- return bitrev32(crc) >> 16;
+ velocity_register_notifier();
+ ret = pci_register_driver(&velocity_driver);
+ if (ret < 0)
+ velocity_unregister_notifier();
+ return ret;
}
/**
- * velocity_set_wol - set up for wake on lan
- * @vptr: velocity to set WOL status on
- *
- * Set a card up for wake on lan either by unicast or by
- * ARP packet.
+ * velocity_cleanup - module unload
*
- * FIXME: check static buffer is safe here
+ * When the velocity hardware is unloaded this function is called.
+ * It will clean up the notifiers and the unregister the PCI
+ * driver interface for this hardware. This in turn cleans up
+ * all discovered interfaces before returning from the function
*/
-
-static int velocity_set_wol(struct velocity_info *vptr)
-{
- struct mac_regs __iomem * regs = vptr->mac_regs;
- static u8 buf[256];
- int i;
-
- static u32 mask_pattern[2][4] = {
- {0x00203000, 0x000003C0, 0x00000000, 0x0000000}, /* ARP */
- {0xfffff000, 0xffffffff, 0xffffffff, 0x000ffff} /* Magic Packet */
- };
-
- writew(0xFFFF, &regs->WOLCRClr);
- writeb(WOLCFG_SAB | WOLCFG_SAM, &regs->WOLCFGSet);
- writew(WOLCR_MAGIC_EN, &regs->WOLCRSet);
-
- /*
- if (vptr->wol_opts & VELOCITY_WOL_PHY)
- writew((WOLCR_LINKON_EN|WOLCR_LINKOFF_EN), &regs->WOLCRSet);
- */
-
- if (vptr->wol_opts & VELOCITY_WOL_UCAST) {
- writew(WOLCR_UNICAST_EN, &regs->WOLCRSet);
- }
-
- if (vptr->wol_opts & VELOCITY_WOL_ARP) {
- struct arp_packet *arp = (struct arp_packet *) buf;
- u16 crc;
- memset(buf, 0, sizeof(struct arp_packet) + 7);
-
- for (i = 0; i < 4; i++)
- writel(mask_pattern[0][i], &regs->ByteMask[0][i]);
-
- arp->type = htons(ETH_P_ARP);
- arp->ar_op = htons(1);
-
- memcpy(arp->ar_tip, vptr->ip_addr, 4);
-
- crc = wol_calc_crc((sizeof(struct arp_packet) + 7) / 8, buf,
- (u8 *) & mask_pattern[0][0]);
-
- writew(crc, &regs->PatternCRC[0]);
- writew(WOLCR_ARP_EN, &regs->WOLCRSet);
- }
-
- BYTE_REG_BITS_ON(PWCFG_WOLTYPE, &regs->PWCFGSet);
- BYTE_REG_BITS_ON(PWCFG_LEGACY_WOLEN, &regs->PWCFGSet);
-
- writew(0x0FFF, &regs->WOLSRClr);
-
- if (vptr->mii_status & VELOCITY_AUTONEG_ENABLE) {
- if (PHYID_GET_PHY_ID(vptr->phy_id) == PHYID_CICADA_CS8201)
- MII_REG_BITS_ON(AUXCR_MDPPS, MII_REG_AUXCR, vptr->mac_regs);
-
- MII_REG_BITS_OFF(G1000CR_1000FD | G1000CR_1000, MII_REG_G1000CR, vptr->mac_regs);
- }
-
- if (vptr->mii_status & VELOCITY_SPEED_1000)
- MII_REG_BITS_ON(BMCR_REAUTO, MII_REG_BMCR, vptr->mac_regs);
-
- BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
-
- {
- u8 GCR;
- GCR = readb(&regs->CHIPGCR);
- GCR = (GCR & ~CHIPGCR_FCGMII) | CHIPGCR_FCFDX;
- writeb(GCR, &regs->CHIPGCR);
- }
-
- BYTE_REG_BITS_OFF(ISR_PWEI, &regs->ISR);
- /* Turn on SWPTAG just before entering power mode */
- BYTE_REG_BITS_ON(STICKHW_SWPTAG, &regs->STICKHW);
- /* Go to bed ..... */
- BYTE_REG_BITS_ON((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
-
- return 0;
-}
-
-static int velocity_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
- unsigned long flags;
-
- if(!netif_running(vptr->dev))
- return 0;
-
- netif_device_detach(vptr->dev);
-
- spin_lock_irqsave(&vptr->lock, flags);
- pci_save_state(pdev);
-#ifdef ETHTOOL_GWOL
- 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);
- } else {
- velocity_save_context(vptr, &vptr->context);
- velocity_shutdown(vptr);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- }
-#else
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
-#endif
- spin_unlock_irqrestore(&vptr->lock, flags);
- return 0;
-}
-
-static int velocity_resume(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = netdev_priv(dev);
- unsigned long flags;
- int i;
-
- if(!netif_running(vptr->dev))
- return 0;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_wake(pdev, 0, 0);
- pci_restore_state(pdev);
-
- mac_wol_reset(vptr->mac_regs);
-
- spin_lock_irqsave(&vptr->lock, flags);
- velocity_restore_context(vptr, &vptr->context);
- velocity_init_registers(vptr, VELOCITY_INIT_WOL);
- mac_disable_int(vptr->mac_regs);
-
- velocity_tx_srv(vptr, 0);
-
- for (i = 0; i < vptr->tx.numq; i++) {
- if (vptr->tx.used[i]) {
- mac_tx_queue_wake(vptr->mac_regs, i);
- }
- }
-
- mac_enable_int(vptr->mac_regs);
- spin_unlock_irqrestore(&vptr->lock, flags);
- netif_device_attach(vptr->dev);
-
- return 0;
-}
-
-#ifdef CONFIG_INET
-
-static int velocity_netdev_event(struct notifier_block *nb, unsigned long notification, void *ptr)
+static void __exit velocity_cleanup_module(void)
{
- struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
- struct net_device *dev = ifa->ifa_dev->dev;
- struct velocity_info *vptr;
- unsigned long flags;
-
- if (dev_net(dev) != &init_net)
- return NOTIFY_DONE;
-
- spin_lock_irqsave(&velocity_dev_list_lock, flags);
- list_for_each_entry(vptr, &velocity_dev_list, list) {
- if (vptr->dev == dev) {
- velocity_get_ip(vptr);
- break;
- }
- }
- spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
-
- return NOTIFY_DONE;
+ velocity_unregister_notifier();
+ pci_unregister_driver(&velocity_driver);
}
-#endif
-#endif
+module_init(velocity_init_module);
+module_exit(velocity_cleanup_module);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index 4cd3f6c9737..2f00c13ab50 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -96,8 +96,8 @@
* Bits in the CSM register
*/
-#define CSM_IPOK 0x40 //IP Checkusm validatiaon ok
-#define CSM_TUPOK 0x20 //TCP/UDP Checkusm validatiaon ok
+#define CSM_IPOK 0x40 //IP Checksum validation ok
+#define CSM_TUPOK 0x20 //TCP/UDP Checksum validation ok
#define CSM_FRAG 0x10 //Fragment IP datagram
#define CSM_IPKT 0x04 //Received an IP packet
#define CSM_TCPKT 0x02 //Received a TCP packet
@@ -819,7 +819,7 @@ enum velocity_owner {
* Bits in the EECSR register
*/
-#define EECSR_EMBP 0x40 /* eeprom embeded programming */
+#define EECSR_EMBP 0x40 /* eeprom embedded programming */
#define EECSR_RELOAD 0x20 /* eeprom content reload */
#define EECSR_DPM 0x10 /* eeprom direct programming */
#define EECSR_ECS 0x08 /* eeprom CS pin */
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 2a6e81d5b57..a6f903f0092 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -774,6 +774,7 @@ static struct ethtool_ops virtnet_ethtool_ops = {
.set_tx_csum = virtnet_set_tx_csum,
.set_sg = ethtool_op_set_sg,
.set_tso = ethtool_op_set_tso,
+ .set_ufo = ethtool_op_set_ufo,
.get_link = ethtool_op_get_link,
};
@@ -1005,7 +1006,7 @@ static unsigned int features[] = {
VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
- VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
+ VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
VIRTIO_F_NOTIFY_ON_EMPTY,
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 58d2551c78e..9e94c4b0fb1 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -313,14 +313,6 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
hldev->kdfc = (u8 __iomem *)(hldev->bar0 +
VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
break;
- case 2:
- hldev->kdfc = (u8 __iomem *)(hldev->bar1 +
- VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
- break;
- case 4:
- hldev->kdfc = (u8 __iomem *)(hldev->bar2 +
- VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64));
- break;
default:
break;
}
@@ -831,8 +823,6 @@ vxge_hw_device_initialize(
sizeof(struct vxge_hw_device_config));
hldev->bar0 = attr->bar0;
- hldev->bar1 = attr->bar1;
- hldev->bar2 = attr->bar2;
hldev->pdev = attr->pdev;
hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up;
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index afbdf6f4d22..224acea771e 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -682,8 +682,6 @@ struct __vxge_hw_vpath_handle{
* @major_revision: PCI Device major revision
* @minor_revision: PCI Device minor revision
* @bar0: BAR0 virtual address.
- * @bar1: BAR1 virtual address.
- * @bar2: BAR2 virtual address.
* @pdev: Physical device handle
* @config: Confguration passed by the LL driver at initialization
* @link_state: Link state
@@ -698,8 +696,6 @@ struct __vxge_hw_device {
u8 major_revision;
u8 minor_revision;
void __iomem *bar0;
- void __iomem *bar1;
- void __iomem *bar2;
struct pci_dev *pdev;
struct net_device *ndev;
struct vxge_hw_device_config config;
@@ -788,17 +784,13 @@ struct vxge_hw_device_hw_info {
/**
* struct vxge_hw_device_attr - Device memory spaces.
* @bar0: BAR0 virtual address.
- * @bar1: BAR1 virtual address.
- * @bar2: BAR2 virtual address.
* @pdev: PCI device object.
*
- * Device memory spaces. Includes configuration, BAR0, BAR1, etc. per device
+ * Device memory spaces. Includes configuration, BAR0 etc. per device
* mapped memories. Also, includes a pointer to OS-specific PCI device object.
*/
struct vxge_hw_device_attr {
void __iomem *bar0;
- void __iomem *bar1;
- void __iomem *bar2;
struct pci_dev *pdev;
struct vxge_hw_uld_cbs uld_callbacks;
};
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index 6034497536a..7b5402b50d0 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -374,10 +374,10 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan,
if (ring->vlgrp && ext_info->vlan &&
(ring->vlan_tag_strip ==
VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
- vlan_gro_receive(&ring->napi, ring->vlgrp,
+ vlan_gro_receive(ring->napi_p, ring->vlgrp,
ext_info->vlan, skb);
else
- napi_gro_receive(&ring->napi, skb);
+ napi_gro_receive(ring->napi_p, skb);
} else {
if (ring->vlgrp && vlan &&
(ring->vlan_tag_strip ==
@@ -454,6 +454,8 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
vxge_hw_ring_rxd_1b_get(ringh, dtr, &dma_sizes);
pkt_length = dma_sizes;
+ pkt_length -= ETH_FCS_LEN;
+
vxge_debug_rx(VXGE_TRACE,
"%s: %s:%d Packet Length = %d",
ring->ndev->name, __func__, __LINE__, pkt_length);
@@ -817,7 +819,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
u64 dma_pointer;
struct vxge_tx_priv *txdl_priv = NULL;
struct __vxge_hw_fifo *fifo_hw;
- u32 max_mss = 0x0;
int offload_type;
unsigned long flags = 0;
int vpath_no = 0;
@@ -969,10 +970,6 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
int mss = vxge_tcp_mss(skb);
if (mss) {
- max_mss = dev->mtu + ETH_HLEN -
- VXGE_HW_TCPIP_HEADER_MAX_SIZE;
- if (mss > max_mss)
- mss = max_mss;
vxge_debug_tx(VXGE_TRACE,
"%s: %s:%d mss = %d",
dev->name, __func__, __LINE__, mss);
@@ -1000,7 +997,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
VXGE_COMPLETE_VPATH_TX(fifo);
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...",
dev->name, __func__, __LINE__);
- return 0;
+ return NETDEV_TX_OK;
_exit0:
vxge_debug_tx(VXGE_TRACE, "%s: pci_map_page failed", dev->name);
@@ -1024,7 +1021,7 @@ _exit2:
spin_unlock_irqrestore(&fifo->tx_lock, flags);
VXGE_COMPLETE_VPATH_TX(fifo);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2137,16 +2134,16 @@ int vxge_open_vpaths(struct vxgedev *vdev)
*/
static irqreturn_t vxge_isr_napi(int irq, void *dev_id)
{
- struct __vxge_hw_device *hldev = (struct __vxge_hw_device *)dev_id;
- struct vxgedev *vdev;
struct net_device *dev;
+ struct __vxge_hw_device *hldev;
u64 reason;
enum vxge_hw_status status;
+ struct vxgedev *vdev = (struct vxgedev *) dev_id;;
vxge_debug_intr(VXGE_TRACE, "%s:%d", __func__, __LINE__);
- dev = hldev->ndev;
- vdev = netdev_priv(dev);
+ dev = vdev->ndev;
+ hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev);
if (pci_channel_offline(vdev->pdev))
return IRQ_NONE;
@@ -2417,15 +2414,13 @@ static void vxge_rem_isr(struct vxgedev *vdev)
#endif
if (vdev->config.intr_type == INTA) {
synchronize_irq(vdev->pdev->irq);
- free_irq(vdev->pdev->irq, hldev);
+ free_irq(vdev->pdev->irq, vdev);
}
}
static int vxge_add_isr(struct vxgedev *vdev)
{
int ret = 0;
- struct __vxge_hw_device *hldev =
- (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
#ifdef CONFIG_PCI_MSI
int vp_idx = 0, intr_idx = 0, intr_cnt = 0, msix_idx = 0, irq_req = 0;
u64 function_mode = vdev->config.device_hw_info.function_mode;
@@ -2579,7 +2574,7 @@ INTA_MODE:
if (vdev->config.intr_type == INTA) {
ret = request_irq((int) vdev->pdev->irq,
vxge_isr_napi,
- IRQF_SHARED, vdev->desc[0], hldev);
+ IRQF_SHARED, vdev->desc[0], vdev);
if (ret) {
vxge_debug_init(VXGE_ERR,
"%s %s-%d: ISR registration failed",
@@ -2712,11 +2707,15 @@ vxge_open(struct net_device *dev)
netif_napi_add(dev, &vdev->napi, vxge_poll_inta,
vdev->config.napi_weight);
napi_enable(&vdev->napi);
+ for (i = 0; i < vdev->no_of_vpath; i++)
+ vdev->vpaths[i].ring.napi_p = &vdev->napi;
} else {
for (i = 0; i < vdev->no_of_vpath; i++) {
netif_napi_add(dev, &vdev->vpaths[i].ring.napi,
vxge_poll_msix, vdev->config.napi_weight);
napi_enable(&vdev->vpaths[i].ring.napi);
+ vdev->vpaths[i].ring.napi_p =
+ &vdev->vpaths[i].ring.napi;
}
}
@@ -2890,6 +2889,9 @@ int do_vxge_close(struct net_device *dev, int do_io)
vdev = (struct vxgedev *)netdev_priv(dev);
hldev = (struct __vxge_hw_device *) pci_get_drvdata(vdev->pdev);
+ if (unlikely(!is_vxge_card_up(vdev)))
+ return 0;
+
/* If vxge_handle_crit_err task is executing,
* wait till it completes. */
while (test_and_set_bit(__VXGE_STATE_RESET_CARD, &vdev->state))
@@ -4152,18 +4154,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
attr.bar0,
(unsigned long long)pci_resource_start(pdev, 0));
- attr.bar1 = pci_ioremap_bar(pdev, 2);
- if (!attr.bar1) {
- vxge_debug_init(VXGE_ERR,
- "%s : cannot remap io memory bar2", __func__);
- ret = -ENODEV;
- goto _exit3;
- }
- vxge_debug_ll_config(VXGE_TRACE,
- "pci ioremap bar1: %p:0x%llx",
- attr.bar1,
- (unsigned long long)pci_resource_start(pdev, 2));
-
status = vxge_hw_device_hw_info_get(attr.bar0,
&ll_config.device_hw_info);
if (status != VXGE_HW_OK) {
@@ -4171,17 +4161,17 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
"%s: Reading of hardware info failed."
"Please try upgrading the firmware.", VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
if (ll_config.device_hw_info.fw_version.major !=
- VXGE_DRIVER_VERSION_MAJOR) {
+ VXGE_DRIVER_FW_VERSION_MAJOR) {
vxge_debug_init(VXGE_ERR,
- "FW Ver.(maj): %d not driver's expected version: %d",
- ll_config.device_hw_info.fw_version.major,
- VXGE_DRIVER_VERSION_MAJOR);
+ "%s: Incorrect firmware version."
+ "Please upgrade the firmware to version 1.x.x",
+ VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vpath_mask = ll_config.device_hw_info.vpath_mask;
@@ -4189,7 +4179,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_ll_config(VXGE_TRACE,
"%s: No vpaths available in device", VXGE_DRIVER_NAME);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vxge_debug_ll_config(VXGE_TRACE,
@@ -4222,7 +4212,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_ll_config(VXGE_ERR,
"%s: No more vpaths to configure", VXGE_DRIVER_NAME);
ret = 0;
- goto _exit4;
+ goto _exit3;
}
/* Setting driver callbacks */
@@ -4235,7 +4225,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_init(VXGE_ERR,
"Failed to initialize device (%d)", status);
ret = -EINVAL;
- goto _exit4;
+ goto _exit3;
}
vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
@@ -4260,7 +4250,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath,
&vdev)) {
ret = -EINVAL;
- goto _exit5;
+ goto _exit4;
}
vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL);
@@ -4271,7 +4261,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
hldev->ndev = vdev->ndev;
vdev->mtu = VXGE_HW_DEFAULT_MTU;
vdev->bar0 = attr.bar0;
- vdev->bar1 = attr.bar1;
vdev->max_vpath_supported = max_vpath_supported;
vdev->no_of_vpath = no_of_vpath;
@@ -4336,6 +4325,27 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
ll_config.device_hw_info.fw_version.version,
ll_config.device_hw_info.fw_date.date);
+ if (new_device) {
+ switch (ll_config.device_hw_info.function_mode) {
+ case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Single Function Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Multi Function Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_SRIOV:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Single Root IOV Mode Enabled", vdev->ndev->name);
+ break;
+ case VXGE_HW_FUNCTION_MODE_MRIOV:
+ vxge_debug_init(VXGE_TRACE,
+ "%s: Multi Root IOV Mode Enabled", vdev->ndev->name);
+ break;
+ }
+ }
+
vxge_print_parm(vdev, vpath_mask);
/* Store the fw version for ethttool option */
@@ -4353,7 +4363,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
"%s: mac_addr_list : memory allocation failed",
vdev->ndev->name);
ret = -EPERM;
- goto _exit6;
+ goto _exit5;
}
macaddr = (u8 *)&entry->macaddr;
memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN);
@@ -4361,6 +4371,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vdev->vpaths[i].mac_addr_cnt = 1;
}
+ kfree(device_config);
vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d Exiting...",
vdev->ndev->name, __func__, __LINE__);
@@ -4370,16 +4381,14 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
return 0;
-_exit6:
+_exit5:
for (i = 0; i < vdev->no_of_vpath; i++)
vxge_free_mac_add_list(&vdev->vpaths[i]);
vxge_device_unregister(hldev);
-_exit5:
+_exit4:
pci_disable_sriov(pdev);
vxge_hw_device_terminate(hldev);
-_exit4:
- iounmap(attr.bar1);
_exit3:
iounmap(attr.bar0);
_exit2:
@@ -4438,7 +4447,6 @@ vxge_remove(struct pci_dev *pdev)
kfree(vdev->vpaths);
iounmap(vdev->bar0);
- iounmap(vdev->bar1);
pci_disable_sriov(pdev);
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 9704b2bd432..18d824c3ab9 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -21,7 +21,7 @@
#define VXGE_DRIVER_NAME "vxge"
#define VXGE_DRIVER_VENDOR "Neterion, Inc"
-#define VXGE_DRIVER_VERSION_MAJOR 0
+#define VXGE_DRIVER_FW_VERSION_MAJOR 1
#define DRV_VERSION VXGE_VERSION_MAJOR"."VXGE_VERSION_MINOR"."\
VXGE_VERSION_FIX"."VXGE_VERSION_BUILD"-"\
@@ -260,6 +260,7 @@ struct vxge_ring {
int gro_enable;
struct napi_struct napi;
+ struct napi_struct *napi_p;
#define VXGE_MAX_MAC_ADDR_COUNT 30
@@ -363,7 +364,6 @@ struct vxgedev {
struct __vxge_hw_vpath_handle *vp_handles[VXGE_HW_MAX_VIRTUAL_PATHS];
void __iomem *bar0;
- void __iomem *bar1;
struct vxge_sw_stats stats;
int mtu;
/* Below variables are used for vpath selection to transmit a packet */
diff --git a/drivers/net/vxge/vxge-reg.h b/drivers/net/vxge/vxge-reg.h
index 10f4da32929..9a3b823e08d 100644
--- a/drivers/net/vxge/vxge-reg.h
+++ b/drivers/net/vxge/vxge-reg.h
@@ -1784,7 +1784,7 @@ struct vxge_hw_mrpcim_reg {
#define VXGE_HW_XMAC_GEN_ERR_REG_XMACJ_XMAC_FSM_ERR vxge_mBIT(63)
/*0x01e18*/ u64 xmac_gen_err_mask;
/*0x01e20*/ u64 xmac_gen_err_alarm;
-/*0x01e28*/ u64 xmac_link_err_port_reg[2];
+/*0x01e28*/ u64 xmac_link_err_port0_reg;
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_DOWN vxge_mBIT(3)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_UP vxge_mBIT(7)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMACJ_PORT_WENT_DOWN vxge_mBIT(11)
@@ -1798,8 +1798,11 @@ struct vxge_hw_mrpcim_reg {
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_RATEMGMT_LASI_INV vxge_mBIT(39)
#define VXGE_HW_XMAC_LINK_ERR_PORT_REG_XMDIO_MDIO_MGR_ACCESS_COMPLETE \
vxge_mBIT(47)
-/*0x01e30*/ u64 xmac_link_err_port_mask[2];
-/*0x01e38*/ u64 xmac_link_err_port_alarm[2];
+/*0x01e30*/ u64 xmac_link_err_port0_mask;
+/*0x01e38*/ u64 xmac_link_err_port0_alarm;
+/*0x01e40*/ u64 xmac_link_err_port1_reg;
+/*0x01e48*/ u64 xmac_link_err_port1_mask;
+/*0x01e50*/ u64 xmac_link_err_port1_alarm;
/*0x01e58*/ u64 xgxs_gen_err_reg;
#define VXGE_HW_XGXS_GEN_ERR_REG_XGXS_XGXS_FSM_ERR vxge_mBIT(63)
/*0x01e60*/ u64 xgxs_gen_err_mask;
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index 7567a1140d0..8260b91fd79 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -35,8 +35,6 @@
VXGE_HW_HEADER_VLAN_SIZE + \
VXGE_HW_HEADER_SNAP_SIZE)
-#define VXGE_HW_TCPIP_HEADER_MAX_SIZE (64 + 64)
-
/* 32bit alignments */
#define VXGE_HW_HEADER_ETHERNET_II_802_3_ALIGN 2
#define VXGE_HW_HEADER_802_2_SNAP_ALIGN 2
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
index 82786ffb7dd..580c6eb077b 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/vxge/vxge-version.h
@@ -18,6 +18,6 @@
#define VXGE_VERSION_MAJOR "2"
#define VXGE_VERSION_MINOR "0"
#define VXGE_VERSION_FIX "4"
-#define VXGE_VERSION_BUILD "17795"
+#define VXGE_VERSION_BUILD "17899"
#define VXGE_VERSION_FOR "k"
#endif
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index f525f9fe74d..4ae9bd297cc 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -663,7 +663,7 @@ static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
free_packet:
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* Get Ethernet-style interface statistics.
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 2fa275a58f9..8526b6d1ee4 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -194,7 +194,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
ret = 0;
if (!skb || !dev)
- return(0);
+ return NETDEV_TX_OK;
dlp = netdev_priv(dev);
@@ -219,7 +219,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
/* Alan Cox recommends always returning 0, and always freeing the packet */
/* experience suggest a slightly more conservative approach */
- if (!ret)
+ if (ret == NETDEV_TX_OK)
{
dev_kfree_skb(skb);
netif_wake_queue(dev);
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 8face5db8f3..e81946d9854 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -1182,7 +1182,7 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (dscc4_tx_quiescent(dpriv, dev))
dscc4_do_tx(dpriv, dev);
- return 0;
+ return NETDEV_TX_OK;
}
static int dscc4_close(struct net_device *dev)
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 25c9ef6a181..20a1237a3d7 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -792,25 +792,6 @@ fst_process_rx_status(int rx_status, char *name)
*/
break;
}
-
- case NET_RX_CN_LOW:
- {
- dbg(DBG_ASS, "%s: Receive Low Congestion\n", name);
- break;
- }
-
- case NET_RX_CN_MOD:
- {
- dbg(DBG_ASS, "%s: Receive Moderate Congestion\n", name);
- break;
- }
-
- case NET_RX_CN_HIGH:
- {
- dbg(DBG_ASS, "%s: Receive High Congestion\n", name);
- break;
- }
-
case NET_RX_DROP:
{
dbg(DBG_ASS, "%s: Received packet dropped\n", name);
@@ -2313,7 +2294,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
dbg(DBG_ASS,
"Tried to transmit but no carrier on card %d port %d\n",
card->card_no, port->index);
- return 0;
+ return NETDEV_TX_OK;
}
/* Drop it if it's too big! MTU failure ? */
@@ -2322,7 +2303,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
LEN_TX_BUFFER);
dev_kfree_skb(skb);
dev->stats.tx_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2356,7 +2337,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_errors++;
dbg(DBG_ASS, "Tx queue overflow card %d port %d\n",
card->card_no, port->index);
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2373,7 +2354,7 @@ fst_start_xmit(struct sk_buff *skb, struct net_device *dev)
fst_q_work_item(&fst_work_txq, card->card_no);
tasklet_schedule(&fst_tx_task);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index bfa0161a02d..52438c76bf8 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -421,7 +421,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
GFP_ATOMIC)) {
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
skb_put(skb, pad);
memset(skb->data + len, 0, pad);
@@ -435,13 +435,13 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_compressed++;
skb->dev = pvc->frad;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
}
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static inline void fr_log_dlci_active(pvc_device *pvc)
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 45b1822c962..d1492ae5d30 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1428,7 +1428,7 @@ static int lmc_start_xmit(struct sk_buff *skb, struct net_device *dev)
lmc_softc_t *sc = dev_to_sc(dev);
u32 flag;
int entry;
- int ret = 0;
+ int ret = NETDEV_TX_OK;
unsigned long flags;
lmc_trace(dev, "lmc_start_xmit in");
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 3fb9dbc88a1..545178e6765 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -465,7 +465,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
prepare_to_send( skb, p );
spin_unlock( &nl->lock );
netif_start_queue( dev );
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -485,7 +485,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
prepare_to_send( skb, dev );
spin_unlock( &nl->lock );
- return 0;
+ return NETDEV_TX_OK;
}
#endif /* CONFIG_SBNI_MULTILINE */
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index e4ad7b6b52e..03b76adbe5f 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -310,7 +310,7 @@ static int wanxl_xmit(struct sk_buff *skb, struct net_device *dev)
}
spin_unlock(&port->lock);
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index d67e208ab37..1047920e742 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -308,7 +308,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_ERR "%s: xmit call when iface is down\n",
dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
switch (skb->data[0]) {
@@ -319,14 +319,14 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
if (err != LAPB_OK)
printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
case 0x02: /* Disconnect request .. do nothing - hang up ?? */
err = lapb_disconnect_request(dev);
if (err != LAPB_OK)
printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
default:
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
skb_pull(skb, 1); /* Remove control byte */
/*
@@ -344,9 +344,9 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
if (err != LAPB_OK) {
printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 2538825d1c6..ea7b29034aa 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -58,6 +58,7 @@
*/
#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
#include "i2400m-sdio.h"
@@ -501,15 +502,12 @@ void i2400ms_remove(struct sdio_func *func)
d_fnend(3, dev, "SDIO func %p\n", func);
}
-enum {
- I2400MS_INTEL_VID = 0x89,
-};
-
static
const struct sdio_device_id i2400ms_sdio_ids[] = {
- /* Intel: i2400m WiMAX over SDIO */
- { SDIO_DEVICE(I2400MS_INTEL_VID, 0x1402) },
- { }, /* end: all zeroes */
+ /* Intel: i2400m WiMAX (iwmc3200) over SDIO */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
+ SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) },
+ { /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 5bc00db21b2..ca7a8a31d0b 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -428,10 +428,12 @@ config RTL8187
Micronet SP907GK V5
Encore ENUWI-G2
Trendnet TEW-424UB
- ASUS P5B Deluxe
+ ASUS P5B Deluxe/P5K Premium motherboards
Toshiba Satellite Pro series of laptops
Asus Wireless Link
- Linksys WUSB54GC-EU
+ Linksys WUSB54GC-EU v2
+ (v1 = rt73usb; v3 is rt2070-based,
+ use staging/rt3070 or try rt2800usb)
Thanks to Realtek for their support!
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 2b9e379994a..5695911bc60 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -452,7 +452,8 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
rx_status.freq = adm8211_channels[priv->channel - 1].center_freq;
rx_status.band = IEEE80211_BAND_2GHZ;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
}
entry = (++priv->cur_rx) % priv->rx_ring_size;
@@ -1963,14 +1964,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM
static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct adm8211_priv *priv = dev->priv;
-
- if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
- ieee80211_stop_queues(dev);
- adm8211_stop(dev);
- }
-
pci_save_state(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
@@ -1978,17 +1971,8 @@ static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
static int adm8211_resume(struct pci_dev *pdev)
{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct adm8211_priv *priv = dev->priv;
-
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
-
- if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
- adm8211_start(dev);
- ieee80211_wake_queues(dev);
- }
-
return 0;
}
#endif /* CONFIG_PM */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 8ce5e4cee16..c150c485857 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1927,7 +1927,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if (!skb) {
airo_print_err(dev->name, "%s: skb == NULL!",__func__);
- return 0;
+ return NETDEV_TX_OK;
}
npacks = skb_queue_len (&ai->txq);
@@ -1938,7 +1938,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
return NETDEV_TX_BUSY;
}
skb_queue_tail (&ai->txq, skb);
- return 0;
+ return NETDEV_TX_OK;
}
spin_lock_irqsave(&ai->aux_lock, flags);
@@ -1951,7 +1951,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) {
set_bit(FLAG_PENDING_XMIT, &ai->flags);
mpi_send_packet (dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -2127,7 +2127,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
if ( skb == NULL ) {
airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return 0;
+ return NETDEV_TX_OK;
}
/* Find a vacant FID */
@@ -2155,7 +2155,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void airo_end_xmit11(struct net_device *dev) {
@@ -2199,7 +2199,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
if ( skb == NULL ) {
airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return 0;
+ return NETDEV_TX_OK;
}
/* Find a vacant FID */
@@ -2227,7 +2227,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) {
wake_up_interruptible(&priv->thr_wait);
} else
airo_end_xmit11(dev);
- return 0;
+ return NETDEV_TX_OK;
}
static void airo_read_stats(struct net_device *dev)
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index d84caf198a2..f96c634e2d3 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1022,7 +1022,7 @@ static int arlan_mac_addr(struct net_device *dev, void *p)
ARLAN_DEBUG_ENTRY("arlan_mac_addr");
return -EINVAL;
- if (!netif_running(dev))
+ if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
@@ -1193,7 +1193,7 @@ static int arlan_tx(struct sk_buff *skb, struct net_device *dev)
arlan_process_interrupt(dev);
ARLAN_DEBUG_EXIT("arlan_tx");
- return 0;
+ return NETDEV_TX_OK;
bad_end:
arlan_process_interrupt(dev);
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 4efbdbe6d6b..13303fa3473 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1568,7 +1568,8 @@ static void at76_rx_tasklet(unsigned long param)
at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
priv->rx_skb->len, priv->rx_skb->data_len);
- ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(priv->rx_skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(priv->hw, priv->rx_skb);
/* Use a new skb for the next receive */
priv->rx_skb = NULL;
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
index bb97981fb24..e6c3ee3e058 100644
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ b/drivers/net/wireless/ath/ar9170/ar9170.h
@@ -109,11 +109,52 @@ struct ar9170_rxstream_mpdu_merge {
bool has_plcp;
};
+#define AR9170_NUM_MAX_BA_RETRY 5
+#define AR9170_NUM_TID 16
+#define WME_BA_BMP_SIZE 64
+#define AR9170_NUM_MAX_AGG_LEN (2 * WME_BA_BMP_SIZE)
+
+#define WME_AC_BE 2
+#define WME_AC_BK 3
+#define WME_AC_VI 1
+#define WME_AC_VO 0
+
+#define TID_TO_WME_AC(_tid) \
+ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
+ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
+ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
+ WME_AC_VO)
+
+#define BAW_WITHIN(_start, _bawsz, _seqno) \
+ ((((_seqno) - (_start)) & 0xfff) < (_bawsz))
+
+enum ar9170_tid_state {
+ AR9170_TID_STATE_INVALID,
+ AR9170_TID_STATE_SHUTDOWN,
+ AR9170_TID_STATE_PROGRESS,
+ AR9170_TID_STATE_COMPLETE,
+};
+
+struct ar9170_sta_tid {
+ struct list_head list;
+ struct sk_buff_head queue;
+ u8 addr[ETH_ALEN];
+ u16 ssn;
+ u16 tid;
+ enum ar9170_tid_state state;
+ bool active;
+ u8 retry;
+};
+
#define AR9170_QUEUE_TIMEOUT 64
#define AR9170_TX_TIMEOUT 8
+#define AR9170_BA_TIMEOUT 4
#define AR9170_JANITOR_DELAY 128
#define AR9170_TX_INVALID_RATE 0xffffffff
+#define AR9170_NUM_TX_STATUS 128
+#define AR9170_NUM_TX_AGG_MAX 30
+
struct ar9170 {
struct ieee80211_hw *hw;
struct mutex mutex;
@@ -187,14 +228,25 @@ struct ar9170 {
struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
struct delayed_work tx_janitor;
+ /* tx ampdu */
+ struct sk_buff_head tx_status_ampdu;
+ spinlock_t tx_ampdu_list_lock;
+ struct list_head tx_ampdu_list;
+ unsigned int tx_ampdu_pending;
/* rxstream mpdu merge */
struct ar9170_rxstream_mpdu_merge rx_mpdu;
struct sk_buff *rx_failover;
int rx_failover_missing;
+
+ /* (cached) HW A-MPDU settings */
+ u8 global_ampdu_density;
+ u8 global_ampdu_factor;
};
struct ar9170_sta_info {
+ struct ar9170_sta_tid agg[AR9170_NUM_TID];
+ unsigned int ampdu_max_len;
};
#define AR9170_TX_FLAG_WAIT_FOR_ACK BIT(0)
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 9d38cf60a0d..c7287a883a4 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -49,6 +49,10 @@ static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+static int modparam_ht;
+module_param_named(ht, modparam_ht, bool, S_IRUGO);
+MODULE_PARM_DESC(ht, "enable MPDU aggregation.");
+
#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
.bitrate = (_bitrate), \
.flags = (_flags), \
@@ -148,12 +152,15 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_40 | \
+ IEEE80211_HT_CAP_GRN_FLD | \
IEEE80211_HT_CAP_DSSSCCK40 | \
IEEE80211_HT_CAP_SM_PS, \
.ampdu_factor = 3, \
.ampdu_density = 6, \
.mcs = { \
- .rx_mask = { 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }, \
+ .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \
+ .rx_highest = cpu_to_le16(300), \
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
}, \
}
@@ -174,8 +181,31 @@ static struct ieee80211_supported_band ar9170_band_5GHz = {
};
static void ar9170_tx(struct ar9170 *ar);
+static bool ar9170_tx_ampdu(struct ar9170 *ar);
-#ifdef AR9170_QUEUE_DEBUG
+static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
+{
+ return le16_to_cpu(hdr->seq_ctrl) >> 4;
+}
+
+static inline u16 ar9170_get_seq(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ return ar9170_get_seq_h((void *) txc->frame_data);
+}
+
+static inline u16 ar9170_get_tid(struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+ struct ieee80211_hdr *hdr = (void *) txc->frame_data;
+
+ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+#define GET_NEXT_SEQ(seq) ((seq + 1) & 0x0fff)
+#define GET_NEXT_SEQ_FROM_SKB(skb) (GET_NEXT_SEQ(ar9170_get_seq(skb)))
+
+#if (defined AR9170_QUEUE_DEBUG) || (defined AR9170_TXAGG_DEBUG)
static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
{
struct ar9170_tx_control *txc = (void *) skb->data;
@@ -183,10 +213,10 @@ static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x "
+ printk(KERN_DEBUG "%s: => FRAME [skb:%p, q:%d, DA:[%pM] flags:%x s:%d "
"mac_ctrl:%04x, phy_ctrl:%08x, timeout:[%d ms]]\n",
wiphy_name(ar->hw->wiphy), skb, skb_get_queue_mapping(skb),
- ieee80211_get_DA(hdr), arinfo->flags,
+ ieee80211_get_DA(hdr), arinfo->flags, ar9170_get_seq_h(hdr),
le16_to_cpu(txc->mac_control), le32_to_cpu(txc->phy_control),
jiffies_to_msecs(arinfo->timeout - jiffies));
}
@@ -210,7 +240,9 @@ static void __ar9170_dump_txqueue(struct ar9170 *ar,
"mismatch %d != %d\n", skb_queue_len(queue), i);
printk(KERN_DEBUG "---[ end ]---\n");
}
+#endif /* AR9170_QUEUE_DEBUG || AR9170_TXAGG_DEBUG */
+#ifdef AR9170_QUEUE_DEBUG
static void ar9170_dump_txqueue(struct ar9170 *ar,
struct sk_buff_head *queue)
{
@@ -220,7 +252,9 @@ static void ar9170_dump_txqueue(struct ar9170 *ar,
__ar9170_dump_txqueue(ar, queue);
spin_unlock_irqrestore(&queue->lock, flags);
}
+#endif /* AR9170_QUEUE_DEBUG */
+#ifdef AR9170_QUEUE_STOP_DEBUG
static void __ar9170_dump_txstats(struct ar9170 *ar)
{
int i;
@@ -229,20 +263,27 @@ static void __ar9170_dump_txstats(struct ar9170 *ar)
wiphy_name(ar->hw->wiphy));
for (i = 0; i < __AR9170_NUM_TXQ; i++)
- printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d\n",
- wiphy_name(ar->hw->wiphy), i, ar->tx_stats[i].limit,
- ar->tx_stats[i].len, skb_queue_len(&ar->tx_status[i]));
+ printk(KERN_DEBUG "%s: queue:%d limit:%d len:%d waitack:%d "
+ " stopped:%d\n", wiphy_name(ar->hw->wiphy), i,
+ ar->tx_stats[i].limit, ar->tx_stats[i].len,
+ skb_queue_len(&ar->tx_status[i]),
+ ieee80211_queue_stopped(ar->hw, i));
}
+#endif /* AR9170_QUEUE_STOP_DEBUG */
-static void ar9170_dump_txstats(struct ar9170 *ar)
+#ifdef AR9170_TXAGG_DEBUG
+static void ar9170_dump_tx_status_ampdu(struct ar9170 *ar)
{
unsigned long flags;
- spin_lock_irqsave(&ar->tx_stats_lock, flags);
- __ar9170_dump_txstats(ar);
- spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
+ spin_lock_irqsave(&ar->tx_status_ampdu.lock, flags);
+ printk(KERN_DEBUG "%s: A-MPDU tx_status queue => \n",
+ wiphy_name(ar->hw->wiphy));
+ __ar9170_dump_txqueue(ar, &ar->tx_status_ampdu);
+ spin_unlock_irqrestore(&ar->tx_status_ampdu.lock, flags);
}
-#endif /* AR9170_QUEUE_DEBUG */
+
+#endif /* AR9170_TXAGG_DEBUG */
/* caller must guarantee exclusive access for _bin_ queue. */
static void ar9170_recycle_expired(struct ar9170 *ar,
@@ -315,6 +356,70 @@ static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
ieee80211_tx_status_irqsafe(ar->hw, skb);
}
+static void ar9170_tx_fake_ampdu_status(struct ar9170 *ar)
+{
+ struct sk_buff_head success;
+ struct sk_buff *skb;
+ unsigned int i;
+ unsigned long queue_bitmap = 0;
+
+ skb_queue_head_init(&success);
+
+ while (skb_queue_len(&ar->tx_status_ampdu) > AR9170_NUM_TX_STATUS)
+ __skb_queue_tail(&success, skb_dequeue(&ar->tx_status_ampdu));
+
+ ar9170_recycle_expired(ar, &ar->tx_status_ampdu, &success);
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: collected %d A-MPDU frames.\n",
+ wiphy_name(ar->hw->wiphy), skb_queue_len(&success));
+ __ar9170_dump_txqueue(ar, &success);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ while ((skb = __skb_dequeue(&success))) {
+ struct ieee80211_tx_info *txinfo;
+
+ queue_bitmap |= BIT(skb_get_queue_mapping(skb));
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(txinfo);
+
+ txinfo->flags |= IEEE80211_TX_STAT_ACK;
+ txinfo->status.rates[0].count = 1;
+
+ skb_pull(skb, sizeof(struct ar9170_tx_control));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+ }
+
+ for_each_bit(i, &queue_bitmap, BITS_PER_BYTE) {
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
+ ieee80211_wake_queue(ar->hw, i);
+ }
+
+ if (queue_bitmap)
+ ar9170_tx(ar);
+}
+
+static void ar9170_tx_ampdu_callback(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
+ struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
+
+ arinfo->timeout = jiffies +
+ msecs_to_jiffies(AR9170_BA_TIMEOUT);
+
+ skb_queue_tail(&ar->tx_status_ampdu, skb);
+ ar9170_tx_fake_ampdu_status(ar);
+ ar->tx_ampdu_pending--;
+
+ if (!list_empty(&ar->tx_ampdu_list) && !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
+}
+
void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -336,7 +441,7 @@ void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
if (arinfo->flags & AR9170_TX_FLAG_BLOCK_ACK) {
- dev_kfree_skb_any(skb);
+ ar9170_tx_ampdu_callback(ar, skb);
} else if (arinfo->flags & AR9170_TX_FLAG_WAIT_FOR_ACK) {
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
@@ -420,6 +525,38 @@ static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
return NULL;
}
+static void ar9170_handle_block_ack(struct ar9170 *ar, u16 count, u16 r)
+{
+ struct sk_buff *skb;
+ struct ieee80211_tx_info *txinfo;
+
+ while (count) {
+ skb = ar9170_get_queued_skb(ar, NULL, &ar->tx_status_ampdu, r);
+ if (!skb)
+ break;
+
+ txinfo = IEEE80211_SKB_CB(skb);
+ ieee80211_tx_info_clear_status(txinfo);
+
+ /* FIXME: maybe more ? */
+ txinfo->status.rates[0].count = 1;
+
+ skb_pull(skb, sizeof(struct ar9170_tx_control));
+ ieee80211_tx_status_irqsafe(ar->hw, skb);
+ count--;
+ }
+
+#ifdef AR9170_TXAGG_DEBUG
+ if (count) {
+ printk(KERN_DEBUG "%s: got %d more failed mpdus, but no more "
+ "suitable frames left in tx_status queue.\n",
+ wiphy_name(ar->hw->wiphy), count);
+
+ ar9170_dump_tx_status_ampdu(ar);
+ }
+#endif /* AR9170_TXAGG_DEBUG */
+}
+
/*
* This worker tries to keeps an maintain tx_status queues.
* So we can guarantee that incoming tx_status reports are
@@ -456,6 +593,8 @@ static void ar9170_tx_janitor(struct work_struct *work)
resched = true;
}
+ ar9170_tx_fake_ampdu_status(ar);
+
if (resched)
queue_delayed_work(ar->hw->workqueue,
&ar->tx_janitor,
@@ -528,8 +667,15 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
break;
case 0xc4:
+ /* BlockACK bitmap */
+ break;
+
case 0xc5:
/* BlockACK events */
+ ar9170_handle_block_ack(ar,
+ le16_to_cpu(cmd->ba_fail_cnt.failed),
+ le16_to_cpu(cmd->ba_fail_cnt.rate));
+ ar9170_tx_fake_ampdu_status(ar);
break;
case 0xc6:
@@ -917,8 +1063,10 @@ static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
ar9170_rx_phy_status(ar, phy, &status);
skb = ar9170_rx_copy_data(buf, mpdu_len);
- if (likely(skb))
- ieee80211_rx_irqsafe(ar->hw, skb, &status);
+ if (likely(skb)) {
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(ar->hw, skb);
+ }
}
void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
@@ -1096,6 +1244,10 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
+ /* set sane AMPDU defaults */
+ ar->global_ampdu_density = 6;
+ ar->global_ampdu_factor = 3;
+
ar->bad_hw_nagger = jiffies;
err = ar->open(ar);
@@ -1141,6 +1293,7 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
flush_workqueue(ar->hw->workqueue);
cancel_delayed_work_sync(&ar->tx_janitor);
+ cancel_delayed_work_sync(&ar->led_work);
cancel_work_sync(&ar->filter_config_work);
cancel_work_sync(&ar->beacon_work);
mutex_lock(&ar->mutex);
@@ -1157,9 +1310,40 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
skb_queue_purge(&ar->tx_pending[i]);
skb_queue_purge(&ar->tx_status[i]);
}
+ skb_queue_purge(&ar->tx_status_ampdu);
+
mutex_unlock(&ar->mutex);
}
+static void ar9170_tx_indicate_immba(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ar9170_tx_control *txc = (void *) skb->data;
+
+ txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_IMM_AMPDU);
+}
+
+static void ar9170_tx_copy_phy(struct ar9170 *ar, struct sk_buff *dst,
+ struct sk_buff *src)
+{
+ struct ar9170_tx_control *dst_txc, *src_txc;
+ struct ieee80211_tx_info *dst_info, *src_info;
+ struct ar9170_tx_info *dst_arinfo, *src_arinfo;
+
+ src_txc = (void *) src->data;
+ src_info = IEEE80211_SKB_CB(src);
+ src_arinfo = (void *) src_info->rate_driver_data;
+
+ dst_txc = (void *) dst->data;
+ dst_info = IEEE80211_SKB_CB(dst);
+ dst_arinfo = (void *) dst_info->rate_driver_data;
+
+ dst_txc->phy_control = src_txc->phy_control;
+
+ /* same MCS for the whole aggregate */
+ memcpy(dst_info->driver_rates, src_info->driver_rates,
+ sizeof(dst_info->driver_rates));
+}
+
static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
@@ -1228,6 +1412,7 @@ static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_AGGR);
arinfo->flags = AR9170_TX_FLAG_BLOCK_ACK;
+
goto out;
}
@@ -1358,6 +1543,159 @@ static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
}
+static bool ar9170_tx_ampdu(struct ar9170 *ar)
+{
+ struct sk_buff_head agg;
+ struct ar9170_sta_tid *tid_info = NULL, *tmp;
+ struct sk_buff *skb, *first = NULL;
+ unsigned long flags, f2;
+ unsigned int i = 0;
+ u16 seq, queue, tmpssn;
+ bool run = false;
+
+ skb_queue_head_init(&agg);
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ if (list_empty(&ar->tx_ampdu_list)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: aggregation list is empty.\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ goto out_unlock;
+ }
+
+ list_for_each_entry_safe(tid_info, tmp, &ar->tx_ampdu_list, list) {
+ if (tid_info->state != AR9170_TID_STATE_COMPLETE) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: dangling aggregation entry!\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ if (++i > 64) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: enough frames aggregated.\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ break;
+ }
+
+ queue = TID_TO_WME_AC(tid_info->tid);
+
+ if (skb_queue_len(&ar->tx_pending[queue]) >=
+ AR9170_NUM_TX_AGG_MAX) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: queue %d full.\n",
+ wiphy_name(ar->hw->wiphy), queue);
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ list_del_init(&tid_info->list);
+
+ spin_lock_irqsave(&tid_info->queue.lock, f2);
+ tmpssn = seq = tid_info->ssn;
+ first = skb_peek(&tid_info->queue);
+
+ if (likely(first))
+ tmpssn = ar9170_get_seq(first);
+
+ if (unlikely(tmpssn != seq)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: ssn mismatch [%d != %d]\n.",
+ wiphy_name(ar->hw->wiphy), seq, tmpssn);
+#endif /* AR9170_TXAGG_DEBUG */
+ tid_info->ssn = tmpssn;
+ }
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generate A-MPDU for tid:%d ssn:%d with "
+ "%d queued frames.\n", wiphy_name(ar->hw->wiphy),
+ tid_info->tid, tid_info->ssn,
+ skb_queue_len(&tid_info->queue));
+ __ar9170_dump_txqueue(ar, &tid_info->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ while ((skb = skb_peek(&tid_info->queue))) {
+ if (unlikely(ar9170_get_seq(skb) != seq))
+ break;
+
+ __skb_unlink(skb, &tid_info->queue);
+ tid_info->ssn = seq = GET_NEXT_SEQ(seq);
+
+ if (unlikely(skb_get_queue_mapping(skb) != queue)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: tid:%d(q:%d) queue:%d "
+ "!match.\n", wiphy_name(ar->hw->wiphy),
+ tid_info->tid,
+ TID_TO_WME_AC(tid_info->tid),
+ skb_get_queue_mapping(skb));
+#endif /* AR9170_TXAGG_DEBUG */
+ dev_kfree_skb_any(skb);
+ continue;
+ }
+
+ if (unlikely(first == skb)) {
+ ar9170_tx_prepare_phy(ar, skb);
+ __skb_queue_tail(&agg, skb);
+ first = skb;
+ } else {
+ ar9170_tx_copy_phy(ar, skb, first);
+ __skb_queue_tail(&agg, skb);
+ }
+
+ if (unlikely(skb_queue_len(&agg) ==
+ AR9170_NUM_TX_AGG_MAX))
+ break;
+ }
+
+ if (skb_queue_empty(&tid_info->queue))
+ tid_info->active = false;
+ else
+ list_add_tail(&tid_info->list,
+ &ar->tx_ampdu_list);
+
+ spin_unlock_irqrestore(&tid_info->queue.lock, f2);
+
+ if (unlikely(skb_queue_empty(&agg))) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: queued empty list!\n",
+ wiphy_name(ar->hw->wiphy));
+#endif /* AR9170_TXAGG_DEBUG */
+ continue;
+ }
+
+ /*
+ * tell the FW/HW that this is the last frame,
+ * that way it will wait for the immediate block ack.
+ */
+ if (likely(skb_peek_tail(&agg)))
+ ar9170_tx_indicate_immba(ar, skb_peek_tail(&agg));
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: generated A-MPDU looks like this:\n",
+ wiphy_name(ar->hw->wiphy));
+ __ar9170_dump_txqueue(ar, &agg);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+
+ spin_lock_irqsave(&ar->tx_pending[queue].lock, flags);
+ skb_queue_splice_tail_init(&agg, &ar->tx_pending[queue]);
+ spin_unlock_irqrestore(&ar->tx_pending[queue].lock, flags);
+ run = true;
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ __skb_queue_purge(&agg);
+
+ return run;
+}
+
static void ar9170_tx(struct ar9170 *ar)
{
struct sk_buff *skb;
@@ -1382,11 +1720,17 @@ static void ar9170_tx(struct ar9170 *ar)
printk(KERN_DEBUG "%s: queue %d full\n",
wiphy_name(ar->hw->wiphy), i);
- __ar9170_dump_txstats(ar);
- printk(KERN_DEBUG "stuck frames: ===> \n");
+ printk(KERN_DEBUG "%s: stuck frames: ===> \n",
+ wiphy_name(ar->hw->wiphy));
ar9170_dump_txqueue(ar, &ar->tx_pending[i]);
ar9170_dump_txqueue(ar, &ar->tx_status[i]);
#endif /* AR9170_QUEUE_DEBUG */
+
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: stop queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_stop_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
continue;
@@ -1401,8 +1745,6 @@ static void ar9170_tx(struct ar9170 *ar)
"remaining slots:%d, needed:%d\n",
wiphy_name(ar->hw->wiphy), i, remaining_space,
frames);
-
- ar9170_dump_txstats(ar);
#endif /* AR9170_QUEUE_DEBUG */
frames = remaining_space;
}
@@ -1430,6 +1772,9 @@ static void ar9170_tx(struct ar9170 *ar)
arinfo->timeout = jiffies +
msecs_to_jiffies(AR9170_TX_TIMEOUT);
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending++;
+
#ifdef AR9170_QUEUE_DEBUG
printk(KERN_DEBUG "%s: send frame q:%d =>\n",
wiphy_name(ar->hw->wiphy), i);
@@ -1438,6 +1783,9 @@ static void ar9170_tx(struct ar9170 *ar)
err = ar->tx(ar, skb);
if (unlikely(err)) {
+ if (arinfo->flags == AR9170_TX_FLAG_BLOCK_ACK)
+ ar->tx_ampdu_pending--;
+
frames_failed++;
dev_kfree_skb_any(skb);
} else {
@@ -1459,13 +1807,18 @@ static void ar9170_tx(struct ar9170 *ar)
if (unlikely(frames_failed)) {
#ifdef AR9170_QUEUE_DEBUG
- printk(KERN_DEBUG "%s: frames failed =>\n",
+ printk(KERN_DEBUG "%s: frames failed %d =>\n",
wiphy_name(ar->hw->wiphy), frames_failed);
#endif /* AR9170_QUEUE_DEBUG */
spin_lock_irqsave(&ar->tx_stats_lock, flags);
ar->tx_stats[i].len -= frames_failed;
ar->tx_stats[i].count -= frames_failed;
+#ifdef AR9170_QUEUE_STOP_DEBUG
+ printk(KERN_DEBUG "%s: wake queue %d\n",
+ wiphy_name(ar->hw->wiphy), i);
+ __ar9170_dump_txstats(ar);
+#endif /* AR9170_QUEUE_STOP_DEBUG */
ieee80211_wake_queue(ar->hw, i);
spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
}
@@ -1477,6 +1830,90 @@ static void ar9170_tx(struct ar9170 *ar)
msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
+static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *txinfo;
+ struct ar9170_sta_info *sta_info;
+ struct ar9170_sta_tid *agg;
+ struct sk_buff *iter;
+ unsigned long flags, f2;
+ unsigned int max;
+ u16 tid, seq, qseq;
+ bool run = false, queue = false;
+
+ tid = ar9170_get_tid(skb);
+ seq = ar9170_get_seq(skb);
+ txinfo = IEEE80211_SKB_CB(skb);
+ sta_info = (void *) txinfo->control.sta->drv_priv;
+ agg = &sta_info->agg[tid];
+ max = sta_info->ampdu_max_len;
+
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+
+ if (unlikely(agg->state != AR9170_TID_STATE_COMPLETE)) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: BlockACK session not fully initialized "
+ "for ESS:%pM tid:%d state:%d.\n",
+ wiphy_name(ar->hw->wiphy), agg->addr, agg->tid,
+ agg->state);
+#endif /* AR9170_TXAGG_DEBUG */
+ goto err_unlock;
+ }
+
+ if (!agg->active) {
+ agg->active = true;
+ agg->ssn = seq;
+ queue = true;
+ }
+
+ /* check if seq is within the BA window */
+ if (unlikely(!BAW_WITHIN(agg->ssn, max, seq))) {
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: frame with tid:%d seq:%d does not "
+ "fit into BA window (%d - %d)\n",
+ wiphy_name(ar->hw->wiphy), tid, seq, agg->ssn,
+ (agg->ssn + max) & 0xfff);
+#endif /* AR9170_TXAGG_DEBUG */
+ goto err_unlock;
+ }
+
+ spin_lock_irqsave(&agg->queue.lock, f2);
+
+ skb_queue_reverse_walk(&agg->queue, iter) {
+ qseq = ar9170_get_seq(iter);
+
+ if (GET_NEXT_SEQ(qseq) == seq) {
+ __skb_queue_after(&agg->queue, iter, skb);
+ goto queued;
+ }
+ }
+
+ __skb_queue_head(&agg->queue, skb);
+
+queued:
+ spin_unlock_irqrestore(&agg->queue.lock, f2);
+
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_DEBUG "%s: new aggregate %p queued.\n",
+ wiphy_name(ar->hw->wiphy), skb);
+ __ar9170_dump_txqueue(ar, &agg->queue);
+#endif /* AR9170_TXAGG_DEBUG */
+
+ if (skb_queue_len(&agg->queue) >= AR9170_NUM_TX_AGG_MAX)
+ run = true;
+
+ if (queue)
+ list_add_tail(&agg->list, &ar->tx_ampdu_list);
+
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ return run;
+
+err_unlock:
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ dev_kfree_skb_irq(skb);
+ return false;
+}
+
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ar9170 *ar = hw->priv;
@@ -1490,8 +1927,10 @@ int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
info = IEEE80211_SKB_CB(skb);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
- /* drop frame, we do not allow TX A-MPDU aggregation yet. */
- goto err_free;
+ bool run = ar9170_tx_ampdu_queue(ar, skb);
+
+ if (run || !ar->tx_ampdu_pending)
+ ar9170_tx_ampdu(ar);
} else {
unsigned int queue = skb_get_queue_mapping(skb);
@@ -1929,6 +2368,53 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ unsigned int i;
+
+ switch (cmd) {
+ case STA_NOTIFY_ADD:
+ memset(sta_info, 0, sizeof(*sta_info));
+
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ if (sta->ht_cap.ampdu_density > ar->global_ampdu_density)
+ ar->global_ampdu_density = sta->ht_cap.ampdu_density;
+
+ if (sta->ht_cap.ampdu_factor < ar->global_ampdu_factor)
+ ar->global_ampdu_factor = sta->ht_cap.ampdu_factor;
+
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_SHUTDOWN;
+ sta_info->agg[i].active = false;
+ sta_info->agg[i].ssn = 0;
+ sta_info->agg[i].retry = 0;
+ sta_info->agg[i].tid = i;
+ INIT_LIST_HEAD(&sta_info->agg[i].list);
+ skb_queue_head_init(&sta_info->agg[i].queue);
+ }
+
+ sta_info->ampdu_max_len = 1 << (3 + sta->ht_cap.ampdu_factor);
+ break;
+
+ case STA_NOTIFY_REMOVE:
+ if (!sta->ht_cap.ht_supported)
+ break;
+
+ for (i = 0; i < AR9170_NUM_TID; i++) {
+ sta_info->agg[i].state = AR9170_TID_STATE_INVALID;
+ skb_queue_purge(&sta_info->agg[i].queue);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (IS_STARTED(ar) && ar->filter_changed)
+ queue_work(ar->hw->workqueue, &ar->filter_config_work);
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
@@ -1983,18 +2469,65 @@ static int ar9170_ampdu_action(struct ieee80211_hw *hw,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
+ struct ar9170 *ar = hw->priv;
+ struct ar9170_sta_info *sta_info = (void *) sta->drv_priv;
+ struct ar9170_sta_tid *tid_info = &sta_info->agg[tid];
+ unsigned long flags;
+
+ if (!modparam_ht)
+ return -EOPNOTSUPP;
+
switch (action) {
+ case IEEE80211_AMPDU_TX_START:
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ if (tid_info->state != AR9170_TID_STATE_SHUTDOWN ||
+ !list_empty(&tid_info->list)) {
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_INFO "%s: A-MPDU [ESS:[%pM] tid:[%d]] "
+ "is in a very bad state!\n",
+ wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+ return -EBUSY;
+ }
+
+ *ssn = tid_info->ssn;
+ tid_info->state = AR9170_TID_STATE_PROGRESS;
+ tid_info->active = false;
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_STOP:
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ tid_info->state = AR9170_TID_STATE_SHUTDOWN;
+ list_del_init(&tid_info->list);
+ tid_info->active = false;
+ skb_queue_purge(&tid_info->queue);
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid);
+ break;
+
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+#ifdef AR9170_TXAGG_DEBUG
+ printk(KERN_INFO "%s: A-MPDU for %pM [tid:%d] Operational.\n",
+ wiphy_name(hw->wiphy), sta->addr, tid);
+#endif /* AR9170_TXAGG_DEBUG */
+ spin_lock_irqsave(&ar->tx_ampdu_list_lock, flags);
+ sta_info->agg[tid].state = AR9170_TID_STATE_COMPLETE;
+ spin_unlock_irqrestore(&ar->tx_ampdu_list_lock, flags);
+ break;
+
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
- /*
- * Something goes wrong -- RX locks up
- * after a while of receiving aggregated
- * frames -- not enabling for now.
- */
- return -EOPNOTSUPP;
+ /* Handled by firmware */
+ break;
+
default:
return -EOPNOTSUPP;
}
+
+ return 0;
}
static const struct ieee80211_ops ar9170_ops = {
@@ -2043,6 +2576,8 @@ void *ar9170_alloc(size_t priv_size)
mutex_init(&ar->mutex);
spin_lock_init(&ar->cmdlock);
spin_lock_init(&ar->tx_stats_lock);
+ spin_lock_init(&ar->tx_ampdu_list_lock);
+ skb_queue_head_init(&ar->tx_status_ampdu);
for (i = 0; i < __AR9170_NUM_TXQ; i++) {
skb_queue_head_init(&ar->tx_status[i]);
skb_queue_head_init(&ar->tx_pending[i]);
@@ -2051,6 +2586,7 @@ void *ar9170_alloc(size_t priv_size)
INIT_WORK(&ar->filter_config_work, ar9170_set_filters);
INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
+ INIT_LIST_HEAD(&ar->tx_ampdu_list);
/* all hw supports 2.4 GHz, so set channel to 1 by default */
ar->channel = &ar9170_2ghz_chantable[0];
@@ -2064,6 +2600,13 @@ void *ar9170_alloc(size_t priv_size)
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
+ if (modparam_ht) {
+ ar->hw->flags |= IEEE80211_HW_AMPDU_AGGREGATION;
+ } else {
+ ar9170_band_2GHz.ht_cap.ht_supported = false;
+ ar9170_band_5GHz.ht_cap.ht_supported = false;
+ }
+
ar->hw->queues = __AR9170_NUM_TXQ;
ar->hw->extra_tx_headroom = 8;
ar->hw->sta_data_size = sizeof(struct ar9170_sta_info);
@@ -2085,10 +2628,10 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
{
#define RW 8 /* number of words to read at once */
#define RB (sizeof(u32) * RW)
- DECLARE_MAC_BUF(mbuf);
u8 *eeprom = (void *)&ar->eeprom;
u8 *addr = ar->eeprom.mac_address;
__le32 offsets[RW];
+ unsigned int rx_streams, tx_streams, tx_params = 0;
int i, j, err, bands = 0;
BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
@@ -2125,6 +2668,20 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
bands++;
}
+
+ rx_streams = hweight8(ar->eeprom.rx_mask);
+ tx_streams = hweight8(ar->eeprom.tx_mask);
+
+ if (rx_streams != tx_streams)
+ tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
+
+ if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
+ tx_params = (tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
+
+ ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
+ ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
+
/*
* I measured this, a bandswitch takes roughly
* 135 ms and a frequency switch about 80.
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 754b1f8d8da..1aec7afdffa 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -779,7 +779,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
aru->req_one_stage_fw = ar9170_requires_one_stage(id);
usb_set_intfdata(intf, aru);
- SET_IEEE80211_DEV(ar->hw, &udev->dev);
+ SET_IEEE80211_DEV(ar->hw, &intf->dev);
init_usb_anchor(&aru->rx_submitted);
init_usb_anchor(&aru->tx_pending);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 6358233bac9..91375113916 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -713,8 +713,8 @@ struct ath5k_gain {
* Used internaly for reset_tx_queue).
* Also see struct struct ieee80211_channel.
*/
-#define IS_CHAN_XR(_c) ((_c.hw_value & CHANNEL_XR) != 0)
-#define IS_CHAN_B(_c) ((_c.hw_value & CHANNEL_B) != 0)
+#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0)
+#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0)
/*
* The following structure is used to map 2GHz channels to
@@ -1029,14 +1029,15 @@ struct ath5k_hw {
enum ath5k_int ah_imr;
enum nl80211_iftype ah_op_mode;
- enum ath5k_power_mode ah_power_mode;
- struct ieee80211_channel ah_current_channel;
+ struct ieee80211_channel *ah_current_channel;
bool ah_turbo;
bool ah_calibration;
- bool ah_running;
bool ah_single_chip;
bool ah_combined_mic;
+ enum ath5k_version ah_version;
+ enum ath5k_radio ah_radio;
+ u32 ah_phy;
u32 ah_mac_srev;
u16 ah_mac_version;
u16 ah_mac_revision;
@@ -1044,13 +1045,6 @@ struct ath5k_hw {
u16 ah_radio_5ghz_revision;
u16 ah_radio_2ghz_revision;
- enum ath5k_version ah_version;
- enum ath5k_radio ah_radio;
- u32 ah_phy;
-
- bool ah_5ghz;
- bool ah_2ghz;
-
#define ah_modes ah_capabilities.cap_mode
#define ah_ee_version ah_capabilities.cap_eeprom.ee_version
@@ -1058,7 +1052,6 @@ struct ath5k_hw {
u32 ah_aifs;
u32 ah_cw_min;
u32 ah_cw_max;
- bool ah_software_retry;
u32 ah_limit_tx_retries;
/* Antenna Control */
@@ -1066,6 +1059,7 @@ struct ath5k_hw {
u8 ah_ant_mode;
u8 ah_tx_ant;
u8 ah_def_ant;
+ bool ah_software_retry;
u8 ah_sta_id[ETH_ALEN];
@@ -1075,7 +1069,6 @@ struct ath5k_hw {
u8 ah_bssid[ETH_ALEN];
u8 ah_bssid_mask[ETH_ALEN];
- u32 ah_gpio[AR5K_MAX_GPIO];
int ah_gpio_npins;
struct ath_regulatory ah_regulatory;
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index c41ef58393e..9a84d9410b2 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -319,6 +319,9 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
ath5k_hw_rfgain_opt_init(ah);
+ /* turn on HW LEDs */
+ ath5k_hw_set_ledstate(ah, AR5K_LED_INIT);
+
return ah;
err_free:
kfree(ah);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 029c1bc7468..7db32ce3dbd 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -218,6 +218,8 @@ static struct pci_driver ath5k_pci_driver = {
* Prototypes - MAC 802.11 stack related functions
*/
static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq);
static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
static int ath5k_reset_wake(struct ath5k_softc *sc);
static int ath5k_start(struct ieee80211_hw *hw);
@@ -248,6 +250,8 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changes);
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw);
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw);
static const struct ieee80211_ops ath5k_hw_ops = {
.tx = ath5k_tx,
@@ -265,6 +269,8 @@ static const struct ieee80211_ops ath5k_hw_ops = {
.set_tsf = ath5k_set_tsf,
.reset_tsf = ath5k_reset_tsf,
.bss_info_changed = ath5k_bss_info_changed,
+ .sw_scan_start = ath5k_sw_scan_start,
+ .sw_scan_complete = ath5k_sw_scan_complete,
};
/*
@@ -297,7 +303,8 @@ static void ath5k_desc_free(struct ath5k_softc *sc,
static int ath5k_rxbuf_setup(struct ath5k_softc *sc,
struct ath5k_buf *bf);
static int ath5k_txbuf_setup(struct ath5k_softc *sc,
- struct ath5k_buf *bf);
+ struct ath5k_buf *bf,
+ struct ath5k_txq *txq);
static inline void ath5k_txbuf_free(struct ath5k_softc *sc,
struct ath5k_buf *bf)
{
@@ -512,6 +519,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
/* Initialize driver private data */
SET_IEEE80211_DEV(hw, &pdev->dev);
hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM;
@@ -666,7 +674,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath5k_led_off(sc);
- free_irq(pdev->irq, sc);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -694,18 +701,8 @@ ath5k_pci_resume(struct pci_dev *pdev)
*/
pci_write_config_byte(pdev, 0x41, 0);
- err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
- if (err) {
- ATH5K_ERR(sc, "request_irq failed\n");
- goto err_no_irq;
- }
-
ath5k_led_enable(sc);
return 0;
-
-err_no_irq:
- pci_disable_device(pdev);
- return err;
}
#endif /* CONFIG_PM */
@@ -785,12 +782,18 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
goto err_desc;
}
sc->bhalq = ret;
+ sc->cabq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_CAB, 0);
+ if (IS_ERR(sc->cabq)) {
+ ATH5K_ERR(sc, "can't setup cab queue\n");
+ ret = PTR_ERR(sc->cabq);
+ goto err_bhal;
+ }
sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK);
if (IS_ERR(sc->txq)) {
ATH5K_ERR(sc, "can't setup xmit queue\n");
ret = PTR_ERR(sc->txq);
- goto err_bhal;
+ goto err_queues;
}
tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
@@ -1228,10 +1231,10 @@ ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
}
static int
-ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
+ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
+ struct ath5k_txq *txq)
{
struct ath5k_hw *ah = sc->ah;
- struct ath5k_txq *txq = sc->txq;
struct ath5k_desc *ds = bf->desc;
struct sk_buff *skb = bf->skb;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1901,7 +1904,8 @@ accept:
if (sc->opmode == NL80211_IFTYPE_ADHOC)
ath5k_check_ibss_tsf(sc, skb, &rxs);
- __ieee80211_rx(sc->hw, skb, &rxs);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rxs, sizeof(rxs));
+ ieee80211_rx(sc->hw, skb);
bf->skb = next_skb;
bf->skbaddr = next_skb_addr;
@@ -2078,13 +2082,6 @@ err_unmap:
return ret;
}
-static void ath5k_beacon_disable(struct ath5k_softc *sc)
-{
- sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- ath5k_hw_set_imr(sc->ah, sc->imask);
- ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
-}
-
/*
* Transmit a beacon frame at SWBA. Dynamic updates to the
* frame contents are done as needed and the slot time is
@@ -2098,6 +2095,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
{
struct ath5k_buf *bf = sc->bbuf;
struct ath5k_hw *ah = sc->ah;
+ struct sk_buff *skb;
ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "in beacon_send\n");
@@ -2151,6 +2149,12 @@ ath5k_beacon_send(struct ath5k_softc *sc)
ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "TXDP[%u] = %llx (%p)\n",
sc->bhalq, (unsigned long long)bf->daddr, bf->desc);
+ skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ while (skb) {
+ ath5k_tx_queue(sc->hw, skb, sc->cabq);
+ skb = ieee80211_get_buffered_bc(sc->hw, sc->vif);
+ }
+
sc->bsent++;
}
@@ -2271,13 +2275,11 @@ ath5k_beacon_config(struct ath5k_softc *sc)
struct ath5k_hw *ah = sc->ah;
unsigned long flags;
- ath5k_hw_set_imr(ah, 0);
+ spin_lock_irqsave(&sc->block, flags);
sc->bmisscount = 0;
sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
- if (sc->opmode == NL80211_IFTYPE_ADHOC ||
- sc->opmode == NL80211_IFTYPE_MESH_POINT ||
- sc->opmode == NL80211_IFTYPE_AP) {
+ if (sc->enable_beacon) {
/*
* In IBSS mode we use a self-linked tx descriptor and let the
* hardware send the beacons automatically. We have to load it
@@ -2290,16 +2292,17 @@ ath5k_beacon_config(struct ath5k_softc *sc)
sc->imask |= AR5K_INT_SWBA;
if (sc->opmode == NL80211_IFTYPE_ADHOC) {
- if (ath5k_hw_hasveol(ah)) {
- spin_lock_irqsave(&sc->block, flags);
+ if (ath5k_hw_hasveol(ah))
ath5k_beacon_send(sc);
- spin_unlock_irqrestore(&sc->block, flags);
- }
} else
ath5k_beacon_update_timers(sc, -1);
+ } else {
+ ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
}
ath5k_hw_set_imr(ah, sc->imask);
+ mmiowb();
+ spin_unlock_irqrestore(&sc->block, flags);
}
static void ath5k_tasklet_beacon(unsigned long data)
@@ -2598,6 +2601,14 @@ static int
ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath5k_softc *sc = hw->priv;
+
+ return ath5k_tx_queue(hw, skb, sc->txq);
+}
+
+static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ath5k_txq *txq)
+{
+ struct ath5k_softc *sc = hw->priv;
struct ath5k_buf *bf;
unsigned long flags;
int hdrlen;
@@ -2641,7 +2652,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
bf->skb = skb;
- if (ath5k_txbuf_setup(sc, bf)) {
+ if (ath5k_txbuf_setup(sc, bf, txq)) {
bf->skb = NULL;
spin_lock_irqsave(&sc->txbuflock, flags);
list_add_tail(&bf->list, &sc->txbuf);
@@ -2676,7 +2687,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
sc->curchan = chan;
sc->curband = &sc->sbands[chan->band];
}
- ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
if (ret) {
ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
goto err;
@@ -2776,7 +2787,6 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
goto end;
ath5k_hw_set_lladdr(sc->ah, mac);
- ath5k_beacon_disable(sc);
sc->vif = NULL;
end:
mutex_unlock(&sc->lock);
@@ -3108,25 +3118,6 @@ out:
return ret;
}
-/*
- * Update the beacon and reconfigure the beacon queues.
- */
-static void
-ath5k_beacon_reconfig(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- int ret;
- unsigned long flags;
- struct ath5k_softc *sc = hw->priv;
-
- spin_lock_irqsave(&sc->block, flags);
- ret = ath5k_beacon_update(hw, vif);
- spin_unlock_irqrestore(&sc->block, flags);
- if (ret == 0) {
- ath5k_beacon_config(sc);
- mmiowb();
- }
-}
-
static void
set_beacon_filter(struct ieee80211_hw *hw, bool enable)
{
@@ -3149,6 +3140,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
{
struct ath5k_softc *sc = hw->priv;
struct ath5k_hw *ah = sc->ah;
+ unsigned long flags;
mutex_lock(&sc->lock);
if (WARN_ON(sc->vif != vif))
@@ -3170,15 +3162,37 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
sc->assoc = bss_conf->assoc;
if (sc->opmode == NL80211_IFTYPE_STATION)
set_beacon_filter(hw, sc->assoc);
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
}
- if (changes & BSS_CHANGED_BEACON &&
- (vif->type == NL80211_IFTYPE_ADHOC ||
- vif->type == NL80211_IFTYPE_MESH_POINT ||
- vif->type == NL80211_IFTYPE_AP)) {
- ath5k_beacon_reconfig(hw, vif);
+ if (changes & BSS_CHANGED_BEACON) {
+ spin_lock_irqsave(&sc->block, flags);
+ ath5k_beacon_update(hw, vif);
+ spin_unlock_irqrestore(&sc->block, flags);
}
+ if (changes & BSS_CHANGED_BEACON_ENABLED)
+ sc->enable_beacon = bss_conf->enable_beacon;
+
+ if (changes & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BEACON_INT))
+ ath5k_beacon_config(sc);
+
unlock:
mutex_unlock(&sc->lock);
}
+
+static void ath5k_sw_scan_start(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ if (!sc->assoc)
+ ath5k_hw_set_ledstate(sc->ah, AR5K_LED_SCAN);
+}
+
+static void ath5k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+ struct ath5k_softc *sc = hw->priv;
+ ath5k_hw_set_ledstate(sc->ah, sc->assoc ?
+ AR5K_LED_ASSOC : AR5K_LED_INIT);
+}
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index f9b7f2f819b..778e422946a 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -114,8 +114,7 @@ struct ath5k_softc {
struct pci_dev *pdev; /* for dma mapping */
void __iomem *iobase; /* address of the device */
struct mutex lock; /* dev-level lock */
- /* FIXME: how many does it really need? */
- struct ieee80211_tx_queue_stats tx_stats[16];
+ struct ieee80211_tx_queue_stats tx_stats[AR5K_NUM_TX_QUEUES];
struct ieee80211_low_level_stats ll_stats;
struct ieee80211_hw *hw; /* IEEE 802.11 common */
struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
@@ -171,9 +170,8 @@ struct ath5k_softc {
struct list_head txbuf; /* transmit buffer */
spinlock_t txbuflock;
unsigned int txbuf_len; /* buf count in txbuf list */
- struct ath5k_txq txqs[2]; /* beacon and tx */
-
- struct ath5k_txq *txq; /* beacon and tx*/
+ struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
+ struct ath5k_txq *txq; /* main tx queue */
struct tasklet_struct txtq; /* tx intr tasklet */
struct ath5k_led tx_led; /* tx led */
@@ -187,10 +185,12 @@ struct ath5k_softc {
bintval, /* beacon interval in TU */
bsent;
unsigned int nexttbtt; /* next beacon time in TU */
+ struct ath5k_txq *cabq; /* content after beacon */
struct timer_list calib_tim; /* calibration timer */
int power_level; /* Requested tx power in dbm */
bool assoc; /* assocate state */
+ bool enable_beacon; /* true if beacons are on */
};
#define ath5k_hw_hasbssidmask(_ah) \
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 4904a07e4b5..747508c15d3 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -380,13 +380,15 @@ ath5k_debug_init_device(struct ath5k_softc *sc)
sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
ath5k_global_debugfs);
- sc->debug.debugfs_debug = debugfs_create_file("debug", S_IWUSR | S_IRUGO,
+ sc->debug.debugfs_debug = debugfs_create_file("debug",
+ S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_debug);
- sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUGO,
+ sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_registers);
- sc->debug.debugfs_beacon = debugfs_create_file("beacon", S_IWUSR | S_IRUGO,
+ sc->debug.debugfs_beacon = debugfs_create_file("beacon",
+ S_IWUSR | S_IRUSR,
sc->debug.debugfs_phydir, sc, &fops_beacon);
sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index a876ca8d69e..2075ba99396 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1085,8 +1085,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
AR5K_PHY_CCKTXCTL_WORLD);
}
- ah->ah_current_channel.center_freq = channel->center_freq;
- ah->ah_current_channel.hw_value = channel->hw_value;
+ ah->ah_current_channel = channel;
ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
return 0;
@@ -1731,7 +1730,7 @@ ath5k_hw_set_fast_div(struct ath5k_hw *ah, u8 ee_mode, bool enable)
void
ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
{
- struct ieee80211_channel *channel = &ah->ah_current_channel;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
bool use_def_for_tx, update_def_on_tx, use_def_for_rts, fast_div;
bool use_def_for_sg;
u8 def_ant, tx_ant, ee_mode;
@@ -3011,7 +3010,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
{
/*Just a try M.F.*/
- struct ieee80211_channel *channel = &ah->ah_current_channel;
+ struct ieee80211_channel *channel = ah->ah_current_channel;
u8 ee_mode;
ATH5K_TRACE(ah->ah_sc);
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 73407b3f53e..6d5aaf00d8b 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -411,7 +411,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
AR5K_QCU_MISC_FRSHED_BCN_SENT_GT |
AR5K_QCU_MISC_CBREXP_DIS |
- AR5K_QCU_MISC_RDY_VEOL_POLICY |
AR5K_QCU_MISC_CBREXP_BCN_DIS);
ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h
index 6809b54a2ad..debad07d990 100644
--- a/drivers/net/wireless/ath/ath5k/reg.h
+++ b/drivers/net/wireless/ath/ath5k/reg.h
@@ -339,9 +339,9 @@
#define AR5K_SISR2 0x008c /* Register Address [5211+] */
#define AR5K_SISR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SISR2_QCU_TXURN_S 0
-#define AR5K_SISR2_MCABT 0x00100000 /* Master Cycle Abort */
-#define AR5K_SISR2_SSERR 0x00200000 /* Signaled System Error */
-#define AR5K_SISR2_DPERR 0x00400000 /* Bus parity error */
+#define AR5K_SISR2_MCABT 0x00010000 /* Master Cycle Abort */
+#define AR5K_SISR2_SSERR 0x00020000 /* Signaled System Error */
+#define AR5K_SISR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SISR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SISR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SISR2_DTIM_SYNC 0x04000000 /* DTIM sync lost [5212+] */
@@ -430,9 +430,9 @@
#define AR5K_SIMR2 0x00ac /* Register Address [5211+] */
#define AR5K_SIMR2_QCU_TXURN 0x000003ff /* Mask for QCU_TXURN */
#define AR5K_SIMR2_QCU_TXURN_S 0
-#define AR5K_SIMR2_MCABT 0x00100000 /* Master Cycle Abort */
-#define AR5K_SIMR2_SSERR 0x00200000 /* Signaled System Error */
-#define AR5K_SIMR2_DPERR 0x00400000 /* Bus parity error */
+#define AR5K_SIMR2_MCABT 0x00010000 /* Master Cycle Abort */
+#define AR5K_SIMR2_SSERR 0x00020000 /* Signaled System Error */
+#define AR5K_SIMR2_DPERR 0x00040000 /* Bus parity error */
#define AR5K_SIMR2_TIM 0x01000000 /* [5212+] */
#define AR5K_SIMR2_CAB_END 0x02000000 /* [5212+] */
#define AR5K_SIMR2_DTIM_SYNC 0x04000000 /* DTIM Sync lost [5212+] */
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index bd0a97a38d3..86733fdb477 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -290,7 +290,6 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
}
commit:
- ah->ah_power_mode = mode;
ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1);
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5efc9345ca0..751885a5df4 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -164,7 +164,6 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define WME_NUM_TID 16
#define ATH_TXBUF 512
#define ATH_TXMAXTRY 13
-#define ATH_11N_TXMAXTRY 10
#define ATH_MGT_TXMAXTRY 4
#define WME_BA_BMP_SIZE 64
#define WME_MAX_BA WME_BA_BMP_SIZE
@@ -226,6 +225,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA)
#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)])
+#define ATH_TX_COMPLETE_POLL_INT 1000
+
enum ATH_AGGR_STATUS {
ATH_AGGR_DONE,
ATH_AGGR_BAW_CLOSED,
@@ -241,6 +242,7 @@ struct ath_txq {
u8 axq_aggr_depth;
u32 axq_totalqueued;
bool stopped;
+ bool axq_tx_inprogress;
struct ath_buf *axq_linkbuf;
/* first desc of the last descriptor that contains CTS */
@@ -272,7 +274,6 @@ struct ath_atx_tid {
int sched;
int paused;
u8 state;
- int addba_exchangeattempts;
};
struct ath_atx_ac {
@@ -292,12 +293,28 @@ struct ath_tx_control {
#define ATH_TX_XRETRY 0x02
#define ATH_TX_BAR 0x04
+#define ATH_RSSI_LPF_LEN 10
+#define RSSI_LPF_THRESHOLD -20
+#define ATH9K_RSSI_BAD 0x80
+#define ATH_RSSI_EP_MULTIPLIER (1<<7)
+#define ATH_EP_MUL(x, mul) ((x) * (mul))
+#define ATH_RSSI_IN(x) (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER))
+#define ATH_LPF_RSSI(x, y, len) \
+ ((x != ATH_RSSI_DUMMY_MARKER) ? (((x) * ((len) - 1) + (y)) / (len)) : (y))
+#define ATH_RSSI_LPF(x, y) do { \
+ if ((y) >= RSSI_LPF_THRESHOLD) \
+ x = ATH_LPF_RSSI((x), ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \
+} while (0)
+#define ATH_EP_RND(x, mul) \
+ ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
+
struct ath_node {
struct ath_softc *an_sc;
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
u16 maxampdu;
u8 mpdudensity;
+ int last_rssi;
};
struct ath_tx {
@@ -541,6 +558,8 @@ struct ath_softc {
int irq;
spinlock_t sc_resetlock;
spinlock_t sc_serial_rw;
+ spinlock_t ani_lock;
+ spinlock_t sc_pm_lock;
struct mutex mutex;
u8 curbssid[ETH_ALEN];
@@ -557,7 +576,7 @@ struct ath_softc {
u32 keymax;
DECLARE_BITMAP(keymap, ATH_KEYMAX);
u8 splitmic;
- atomic_t ps_usecount;
+ unsigned long ps_usecount;
enum ath9k_int imask;
enum ath9k_ht_extprotspacing ht_extprotspacing;
enum ath9k_ht_macmode tx_chan_width;
@@ -590,6 +609,7 @@ struct ath_softc {
#endif
struct ath_bus_ops *bus_ops;
struct ath_beacon_config cur_beacon_conf;
+ struct delayed_work tx_complete_work;
};
struct ath_wiphy {
@@ -654,27 +674,8 @@ static inline int ath_ahb_init(void) { return 0; };
static inline void ath_ahb_exit(void) {};
#endif
-static inline void ath9k_ps_wakeup(struct ath_softc *sc)
-{
- if (atomic_inc_return(&sc->ps_usecount) == 1)
- if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
- sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
- ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE);
- }
-}
-
-static inline void ath9k_ps_restore(struct ath_softc *sc)
-{
- if (atomic_dec_and_test(&sc->ps_usecount))
- if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
- !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
- SC_OP_WAIT_FOR_CAB |
- SC_OP_WAIT_FOR_PSPOLL_DATA |
- SC_OP_WAIT_FOR_TX_ACK)))
- ath9k_hw_setpower(sc->sc_ah,
- sc->sc_ah->restore_mode);
-}
-
+void ath9k_ps_wakeup(struct ath_softc *sc);
+void ath9k_ps_restore(struct ath_softc *sc);
void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
int ath9k_wiphy_add(struct ath_softc *sc);
@@ -690,6 +691,7 @@ void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
struct ath_wiphy *selected);
bool ath9k_wiphy_scanning(struct ath_softc *sc);
void ath9k_wiphy_work(struct work_struct *work);
+bool ath9k_all_wiphys_idle(struct ath_softc *sc);
void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val);
unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 3639a2e6987..45c4ea57616 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -674,13 +674,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
- /*
- * It looks like mac80211 may end up using beacon interval of zero in
- * some cases (at least for mesh point). Avoid getting into an
- * infinite loop by using a bit safer value instead..
- */
- if (intval == 0)
- intval = 100;
/* Pull nexttbtt forward to reflect the current TSF */
@@ -745,6 +738,14 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
iftype = sc->sc_ah->opmode;
}
+ /*
+ * It looks like mac80211 may end up using beacon interval of zero in
+ * some cases (at least for mesh point). Avoid getting into an
+ * infinite loop by using a bit safer value instead. To be safe,
+ * do sanity check on beacon interval for all operating modes.
+ */
+ if (cur_conf->beacon_interval == 0)
+ cur_conf->beacon_interval = 100;
switch (iftype) {
case NL80211_IFTYPE_AP:
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index a32d7e7fecb..1f0c5fe4a68 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -691,15 +691,22 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
{
int i, j;
+ s16 noise_floor;
+
+ if (AR_SREV_9280(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
+ else if (AR_SREV_9285(ah))
+ noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
+ else
+ noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
for (i = 0; i < NUM_NF_READINGS; i++) {
ah->nfCalHist[i].currIndex = 0;
- ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].privNF = noise_floor;
ah->nfCalHist[i].invalidNFcount =
AR_PHY_CCA_FILTERWINDOW_LENGTH;
for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
- ah->nfCalHist[i].nfCalBuffer[j] =
- AR_PHY_CCA_MAX_GOOD_VALUE;
+ ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
}
}
}
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index fe5367f1414..547e697b905 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -25,7 +25,9 @@ extern const struct ath9k_percal_data adc_dc_cal_multi_sample;
extern const struct ath9k_percal_data adc_dc_cal_single_sample;
extern const struct ath9k_percal_data adc_init_dc_cal;
-#define AR_PHY_CCA_MAX_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE -85
+#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE -112
+#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE -118
#define AR_PHY_CCA_MAX_HIGH_VALUE -62
#define AR_PHY_CCA_MIN_BAD_VALUE -140
#define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT 3
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 6d20725d645..9f99f00c144 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -500,31 +500,31 @@ int ath9k_init_debug(struct ath_softc *sc)
goto err;
sc->debug.debugfs_debug = debugfs_create_file("debug",
- S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
+ S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
if (!sc->debug.debugfs_debug)
goto err;
- sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
+ sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUSR,
sc->debug.debugfs_phy, sc, &fops_dma);
if (!sc->debug.debugfs_dma)
goto err;
sc->debug.debugfs_interrupt = debugfs_create_file("interrupt",
- S_IRUGO,
+ S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_interrupt);
if (!sc->debug.debugfs_interrupt)
goto err;
sc->debug.debugfs_rcstat = debugfs_create_file("rcstat",
- S_IRUGO,
+ S_IRUSR,
sc->debug.debugfs_phy,
sc, &fops_rcstat);
if (!sc->debug.debugfs_rcstat)
goto err;
sc->debug.debugfs_wiphy = debugfs_create_file(
- "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc,
+ "wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, sc,
&fops_wiphy);
if (!sc->debug.debugfs_wiphy)
goto err;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index ce0e86c36a8..93e8ce0598a 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -1208,6 +1208,19 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
pModal->xatten2Margin[0]);
REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset,
AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]);
+
+ /* Set the block 1 value to block 0 value */
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN,
+ pModal->bswMargin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN,
+ pModal->xatten2Margin[0]);
+ REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + 0x1000,
+ AR_PHY_GAIN_2GHZ_XATTEN2_DB,
+ pModal->xatten2Db[0]);
}
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
@@ -1215,6 +1228,11 @@ static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset,
AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal);
+ REG_RMW_FIELD(ah, AR_PHY_RXGAIN + 0x1000,
+ AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]);
+
if (AR_SREV_9285_11(ah))
REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14));
}
@@ -1239,7 +1257,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal, 0);
/* Initialize Ant Diversity settings from EEPROM */
- if (pModal->version == 3) {
+ if (pModal->version >= 3) {
ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf);
ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf);
regVal = REG_READ(ah, 0x99ac);
@@ -2516,10 +2534,8 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
targetPowerCck.tPow2x[1];
ratesArray[rate5_5s] = ratesArray[rate5_5l] =
targetPowerCck.tPow2x[2];
- ;
ratesArray[rate11s] = ratesArray[rate11l] =
targetPowerCck.tPow2x[3];
- ;
}
if (IS_CHAN_HT40(chan)) {
for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 34935a8ee59..605803ae9ed 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2345,7 +2345,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_bb(ah, chan);
if (!ath9k_hw_init_cal(ah, chan))
- return -EIO;;
+ return -EIO;
rx_chainmask = ah->rxchainmask;
if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -2728,7 +2728,8 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)
return true;
}
-bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+static bool ath9k_hw_setpower_nolock(struct ath_hw *ah,
+ enum ath9k_power_mode mode)
{
int status = true, setChip = true;
static const char *modes[] = {
@@ -2762,6 +2763,55 @@ bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
return status;
}
+bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&ah->ah_sc->sc_pm_lock, flags);
+ ret = ath9k_hw_setpower_nolock(ah, mode);
+ spin_unlock_irqrestore(&ah->ah_sc->sc_pm_lock, flags);
+
+ return ret;
+}
+
+void ath9k_ps_wakeup(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (++sc->ps_usecount != 1)
+ goto unlock;
+
+ if (sc->sc_ah->power_mode != ATH9K_PM_AWAKE) {
+ sc->sc_ah->restore_mode = sc->sc_ah->power_mode;
+ ath9k_hw_setpower_nolock(sc->sc_ah, ATH9K_PM_AWAKE);
+ }
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
+void ath9k_ps_restore(struct ath_softc *sc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->sc_pm_lock, flags);
+ if (--sc->ps_usecount != 0)
+ goto unlock;
+
+ if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
+ !(sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
+ SC_OP_WAIT_FOR_CAB |
+ SC_OP_WAIT_FOR_PSPOLL_DATA |
+ SC_OP_WAIT_FOR_TX_ACK)))
+ ath9k_hw_setpower_nolock(sc->sc_ah,
+ sc->sc_ah->restore_mode);
+
+ unlock:
+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
+}
+
/*
* Helper for ASPM support.
*
@@ -3305,7 +3355,6 @@ void ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
if (eeval & AR5416_OPFLAGS_11G) {
- set_bit(ATH9K_MODE_11B, pCap->wireless_modes);
set_bit(ATH9K_MODE_11G, pCap->wireless_modes);
if (ah->config.ht_enable) {
if (!(eeval & AR5416_OPFLAGS_N_2G_HT20))
@@ -3791,19 +3840,14 @@ void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
void ath9k_hw_reset_tsf(struct ath_hw *ah)
{
- int count;
+ ath9k_ps_wakeup(ah->ah_sc);
+ if (!ath9k_hw_wait(ah, AR_SLP32_MODE, AR_SLP32_TSF_WRITE_STATUS, 0,
+ AH_TSF_WRITE_TIMEOUT))
+ DPRINTF(ah->ah_sc, ATH_DBG_RESET,
+ "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
- count = 0;
- while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) {
- count++;
- if (count > 10) {
- DPRINTF(ah->ah_sc, ATH_DBG_RESET,
- "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n");
- break;
- }
- udelay(10);
- }
REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE);
+ ath9k_ps_restore(ah->ah_sc);
}
bool ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting)
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 9d0b31ad460..28bffdb365a 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -95,6 +95,7 @@
#define MAX_RATE_POWER 63
#define AH_WAIT_TIMEOUT 100000 /* (us) */
+#define AH_TSF_WRITE_TIMEOUT 100 /* (us) */
#define AH_TIME_QUANTUM 10
#define AR_KEYTABLE_SIZE 128
#define POWER_UP_TIME 200000
@@ -113,15 +114,14 @@
enum wireless_mode {
ATH9K_MODE_11A = 0,
- ATH9K_MODE_11B = 2,
- ATH9K_MODE_11G = 3,
- ATH9K_MODE_11NA_HT20 = 6,
- ATH9K_MODE_11NG_HT20 = 7,
- ATH9K_MODE_11NA_HT40PLUS = 8,
- ATH9K_MODE_11NA_HT40MINUS = 9,
- ATH9K_MODE_11NG_HT40PLUS = 10,
- ATH9K_MODE_11NG_HT40MINUS = 11,
- ATH9K_MODE_MAX
+ ATH9K_MODE_11G,
+ ATH9K_MODE_11NA_HT20,
+ ATH9K_MODE_11NG_HT20,
+ ATH9K_MODE_11NA_HT40PLUS,
+ ATH9K_MODE_11NA_HT40MINUS,
+ ATH9K_MODE_11NG_HT40PLUS,
+ ATH9K_MODE_11NG_HT40MINUS,
+ ATH9K_MODE_MAX,
};
enum ath9k_hw_caps {
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index e2f0a34b79a..f67a2a96cc5 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -2782,7 +2782,7 @@ static const u32 ar9280Common_9280_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x000107ff },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafa68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -3439,7 +3439,7 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
{0x00004044, 0x00000000 },
};
-/* AR9285 */
+/* AR9285 Revsion 10*/
static const u_int32_t ar9285Modes_9285[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -3955,7 +3955,7 @@ static const u_int32_t ar9285Common_9285[][2] = {
{ 0x00008338, 0x00000000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4121,8 +4121,9 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
{0x00004044, 0x00000000 },
};
-/* AR9285 v1_2 PCI Register Writes. Created: 03/04/09 */
+/* AR9285 v1_2 PCI Register Writes. Created: 04/13/09 */
static const u_int32_t ar9285Modes_9285_1_2[][6] = {
+ /* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
{ 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -4139,6 +4140,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e },
{ 0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0 },
{ 0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
+ { 0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059 },
{ 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 },
{ 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e },
{ 0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e },
@@ -4419,6 +4421,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
{ 0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000 },
{ 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 },
{ 0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
+ { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000 },
{ 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
{ 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
{ 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
@@ -4618,7 +4621,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
{ 0x00008338, 0x00ff0000 },
{ 0x0000833c, 0x00000000 },
{ 0x00008340, 0x00010380 },
- { 0x00008344, 0x00581043 },
+ { 0x00008344, 0x00481043 },
{ 0x00009808, 0x00000000 },
{ 0x0000980c, 0xafe68e30 },
{ 0x00009810, 0xfd14e000 },
@@ -4752,18 +4755,18 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
/* Address 5G-HT20 5G-HT40 2G-HT40 2G-HT20 Turbo */
{ 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
- { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 },
- { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+ { 0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000 },
+ { 0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000 },
{ 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
{ 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
- { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 },
- { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 },
- { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 },
- { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 },
- { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 },
- { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 },
- { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 },
- { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+ { 0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000 },
+ { 0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000 },
+ { 0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000 },
+ { 0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000 },
+ { 0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000 },
+ { 0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000 },
+ { 0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+ { 0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000 },
{ 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
{ 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
{ 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
@@ -4776,13 +4779,13 @@ static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
{ 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
{ 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
{ 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
- { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
- { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
- { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
- { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
+ { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652 },
+ { 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7 },
+ { 0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
+ { 0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
+ { 0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7 },
};
static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 8ae4ec21667..6f923e31872 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -825,13 +825,29 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen;
ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp;
- ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
- ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00);
- ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01);
- ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02);
- ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10);
- ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11);
- ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12);
+ if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
+ ds->ds_rxstat.rs_rssi = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl0 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl1 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ctl2 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext0 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext1 = ATH9K_RSSI_BAD;
+ ds->ds_rxstat.rs_rssi_ext2 = ATH9K_RSSI_BAD;
+ } else {
+ ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+ ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt00);
+ ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt01);
+ ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt02);
+ ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt10);
+ ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt11);
+ ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt12);
+ }
if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx);
else
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 66a6c1f5022..3436295e050 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -342,6 +342,7 @@ static void ath_ani_calibrate(unsigned long data)
* don't calibrate when we're scanning.
* we are most likely not on our home channel.
*/
+ spin_lock(&sc->ani_lock);
if (sc->sc_flags & SC_OP_SCANNING)
goto set_timer;
@@ -405,6 +406,7 @@ static void ath_ani_calibrate(unsigned long data)
ath9k_ps_restore(sc);
set_timer:
+ spin_unlock(&sc->ani_lock);
/*
* Set timer interval based on previous results.
* The interval must be the shortest necessary to satisfy ANI,
@@ -463,6 +465,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
sta->ht_cap.ampdu_factor);
an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density);
+ an->last_rssi = ATH_RSSI_DUMMY_MARKER;
}
}
@@ -887,6 +890,7 @@ static void setup_ht_cap(struct ath_softc *sc,
{
#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */
#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */
+ u8 tx_streams, rx_streams;
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
@@ -899,45 +903,43 @@ static void setup_ht_cap(struct ath_softc *sc,
/* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+ tx_streams = !(sc->tx_chainmask & (sc->tx_chainmask - 1)) ? 1 : 2;
+ rx_streams = !(sc->rx_chainmask & (sc->rx_chainmask - 1)) ? 1 : 2;
- switch(sc->rx_chainmask) {
- case 1:
- ht_info->mcs.rx_mask[0] = 0xff;
- break;
- case 3:
- case 5:
- case 7:
- default:
- ht_info->mcs.rx_mask[0] = 0xff;
- ht_info->mcs.rx_mask[1] = 0xff;
- break;
+ if (tx_streams != rx_streams) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+ ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
}
- ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+ ht_info->mcs.rx_mask[0] = 0xff;
+ if (rx_streams >= 2)
+ ht_info->mcs.rx_mask[1] = 0xff;
+
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
{
- struct ath_vif *avp = (void *)vif->drv_priv;
if (bss_conf->assoc) {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n",
bss_conf->aid, sc->curbssid);
/* New association, store aid */
- if (avp->av_opmode == NL80211_IFTYPE_STATION) {
- sc->curaid = bss_conf->aid;
- ath9k_hw_write_associd(sc);
+ sc->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc);
- /*
- * Request a re-configuration of Beacon related timers
- * on the receipt of the first Beacon frame (i.e.,
- * after time sync with the AP).
- */
- sc->sc_flags |= SC_OP_BEACON_SYNC;
- }
+ /*
+ * Request a re-configuration of Beacon related timers
+ * on the receipt of the first Beacon frame (i.e.,
+ * after time sync with the AP).
+ */
+ sc->sc_flags |= SC_OP_BEACON_SYNC;
/* Configure the beacon */
ath_beacon_config(sc, vif);
@@ -952,6 +954,8 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
} else {
DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
sc->curaid = 0;
+ /* Stop ANI */
+ del_timer_sync(&sc->ani.timer);
}
}
@@ -1255,6 +1259,7 @@ void ath_detach(struct ath_softc *sc)
ath_deinit_leds(sc);
cancel_work_sync(&sc->chan_work);
cancel_delayed_work_sync(&sc->wiphy_work);
+ cancel_delayed_work_sync(&sc->tx_complete_work);
for (i = 0; i < sc->num_sec_wiphy; i++) {
struct ath_wiphy *aphy = sc->sec_wiphy[i];
@@ -1281,7 +1286,6 @@ void ath_detach(struct ath_softc *sc)
ath9k_hw_detach(sc->sc_ah);
ath9k_exit_debug(sc);
- ath9k_ps_restore(sc);
}
static int ath9k_reg_notifier(struct wiphy *wiphy,
@@ -1311,6 +1315,8 @@ static int ath_init(u16 devid, struct ath_softc *sc)
spin_lock_init(&sc->wiphy_lock);
spin_lock_init(&sc->sc_resetlock);
spin_lock_init(&sc->sc_serial_rw);
+ spin_lock_init(&sc->ani_lock);
+ spin_lock_init(&sc->sc_pm_lock);
mutex_init(&sc->mutex);
tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
@@ -1536,7 +1542,8 @@ void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
hw->max_rates = 4;
hw->channel_change_time = 5000;
hw->max_listen_interval = 10;
- hw->max_rate_tries = ATH_11N_TXMAXTRY;
+ /* Hardware supports 10 but we use 4 */
+ hw->max_rate_tries = 4;
hw->sta_data_size = sizeof(struct ath_node);
hw->vif_data_size = sizeof(struct ath_vif);
@@ -1973,6 +1980,8 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_wake_queues(hw);
+ queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0);
+
mutex_unlock:
mutex_unlock(&sc->mutex);
@@ -2092,8 +2101,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
mutex_lock(&sc->mutex);
- ieee80211_stop_queues(hw);
-
if (ath9k_wiphy_started(sc)) {
mutex_unlock(&sc->mutex);
return; /* another wiphy still in use */
@@ -2196,7 +2203,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
- if (conf->type == NL80211_IFTYPE_AP)
+ if (conf->type == NL80211_IFTYPE_AP ||
+ conf->type == NL80211_IFTYPE_ADHOC ||
+ conf->type == NL80211_IFTYPE_MONITOR)
ath_start_ani(sc);
out:
@@ -2249,9 +2258,28 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
struct ath_softc *sc = aphy->sc;
struct ieee80211_conf *conf = &hw->conf;
struct ath_hw *ah = sc->sc_ah;
+ bool all_wiphys_idle = false, disable_radio = false;
mutex_lock(&sc->mutex);
+ /* Leave this as the first check */
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+
+ spin_lock_bh(&sc->wiphy_lock);
+ all_wiphys_idle = ath9k_all_wiphys_idle(sc);
+ spin_unlock_bh(&sc->wiphy_lock);
+
+ if (conf->flags & IEEE80211_CONF_IDLE){
+ if (all_wiphys_idle)
+ disable_radio = true;
+ }
+ else if (all_wiphys_idle) {
+ ath_radio_enable(sc);
+ DPRINTF(sc, ATH_DBG_CONFIG,
+ "not-idle: enabling radio\n");
+ }
+ }
+
if (changed & IEEE80211_CONF_CHANGE_PS) {
if (conf->flags & IEEE80211_CONF_PS) {
if (!(ah->caps.hw_caps &
@@ -2319,6 +2347,11 @@ skip_chan_change:
if (changed & IEEE80211_CONF_CHANGE_POWER)
sc->config.txpowlimit = 2 * conf->power_level;
+ if (disable_radio) {
+ DPRINTF(sc, ATH_DBG_CONFIG, "idle: disabling radio\n");
+ ath_radio_disable(sc);
+ }
+
mutex_unlock(&sc->mutex);
return 0;
@@ -2681,9 +2714,9 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
aphy->state = ATH_WIPHY_SCAN;
ath9k_wiphy_pause_all_forced(sc, aphy);
- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
sc->sc_flags |= SC_OP_SCANNING;
- mutex_unlock(&sc->mutex);
+ spin_unlock_bh(&sc->ani_lock);
}
static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
@@ -2691,11 +2724,11 @@ static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
- mutex_lock(&sc->mutex);
+ spin_lock_bh(&sc->ani_lock);
aphy->state = ATH_WIPHY_ACTIVE;
sc->sc_flags &= ~SC_OP_SCANNING;
sc->sc_flags |= SC_OP_FULL_RESET;
- mutex_unlock(&sc->mutex);
+ spin_unlock_bh(&sc->ani_lock);
}
struct ieee80211_ops ath9k_ops = {
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index ba06e78b2f5..a07efa22551 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -22,133 +22,132 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 0, 2, 1, 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 0, 3, 1, 1, 1, 1, 1, 0 },
+ 0, 1, 1, 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
- 2, 4, 2, 2, 2, 2, 2, 0 },
+ 2, 2, 2, 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 2, 6, 2, 3, 3, 3, 3, 0 },
+ 2, 3, 3, 3, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
- 4, 10, 3, 4, 4, 4, 4, 0 },
+ 4, 4, 4, 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 4, 14, 3, 5, 5, 5, 5, 0 },
+ 4, 5, 5, 5, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 4, 20, 3, 6, 6, 6, 6, 0 },
+ 4, 6, 6, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 4, 23, 3, 7, 7, 7, 7, 0 },
+ 4, 7, 7, 7, 7, 0 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
- 0, 2, 3, 8, 24, 8, 24, 3216 },
+ 0, 8, 24, 8, 24, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
- 2, 4, 3, 9, 25, 9, 25, 6434 },
+ 2, 9, 25, 9, 25, 6434 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
- 2, 6, 3, 10, 26, 10, 26, 9650 },
+ 2, 10, 26, 10, 26, 9650 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
- 4, 10, 3, 11, 27, 11, 27, 12868 },
+ 4, 11, 27, 11, 27, 12868 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
- 4, 14, 3, 12, 28, 12, 28, 19304 },
+ 4, 12, 28, 12, 28, 19304 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
- 4, 20, 3, 13, 29, 13, 29, 25740 },
+ 4, 13, 29, 13, 29, 25740 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
- 4, 23, 3, 14, 30, 14, 30, 28956 },
+ 4, 14, 30, 14, 30, 28956 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 15, 32, 32180 },
+ 4, 15, 31, 15, 32, 32180 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00,
- 8, 0, 2, 3, 16, 33, 16, 33, 6430 },
+ 8, 3, 16, 33, 16, 33, 6430 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
- 2, 4, 3, 17, 34, 17, 34, 12860 },
+ 2, 17, 34, 17, 34, 12860 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
- 2, 6, 3, 18, 35, 18, 35, 19300 },
+ 2, 18, 35, 18, 35, 19300 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
- 4, 10, 3, 19, 36, 19, 36, 25736 },
+ 4, 19, 36, 19, 36, 25736 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
- 4, 14, 3, 20, 37, 20, 37, 38600 },
+ 4, 20, 37, 20, 37, 38600 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
- 4, 20, 3, 21, 38, 21, 38, 51472 },
+ 4, 21, 38, 21, 38, 51472 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
- 4, 23, 3, 22, 39, 22, 39, 57890 },
+ 4, 22, 39, 22, 39, 57890 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 23, 41, 64320 },
+ 4, 23, 40, 23, 41, 64320 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
- 0, 2, 3, 8, 24, 24, 24, 6684 },
+ 0, 8, 24, 24, 24, 6684 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
- 2, 4, 3, 9, 25, 25, 25, 13368 },
+ 2, 9, 25, 25, 25, 13368 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
- 2, 6, 3, 10, 26, 26, 26, 20052 },
+ 2, 10, 26, 26, 26, 20052 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
- 4, 10, 3, 11, 27, 27, 27, 26738 },
+ 4, 11, 27, 27, 27, 26738 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
- 4, 14, 3, 12, 28, 28, 28, 40104 },
+ 4, 12, 28, 28, 28, 40104 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
- 4, 20, 3, 13, 29, 29, 29, 53476 },
+ 4, 13, 29, 29, 29, 53476 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
- 4, 23, 3, 14, 30, 30, 30, 60156 },
+ 4, 14, 30, 30, 30, 60156 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 32, 32, 66840 },
+ 4, 15, 31, 32, 32, 66840 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
- 4, 25, 3, 15, 31, 32, 32, 74200 },
+ 4, 15, 31, 32, 32, 74200 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
- 0, 2, 3, 16, 33, 33, 33, 13360 },
+ 0, 16, 33, 33, 33, 13360 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
- 2, 4, 3, 17, 34, 34, 34, 26720 },
+ 2, 17, 34, 34, 34, 26720 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
- 2, 6, 3, 18, 35, 35, 35, 40080 },
+ 2, 18, 35, 35, 35, 40080 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
- 4, 10, 3, 19, 36, 36, 36, 53440 },
+ 4, 19, 36, 36, 36, 53440 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
- 4, 14, 3, 20, 37, 37, 37, 80160 },
+ 4, 20, 37, 37, 37, 80160 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
- 4, 20, 3, 21, 38, 38, 38, 106880 },
+ 4, 21, 38, 38, 38, 106880 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
- 4, 23, 3, 22, 39, 39, 39, 120240 },
+ 4, 22, 39, 39, 39, 120240 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 41, 41, 133600 },
+ 4, 23, 40, 41, 41, 133600 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
- 4, 25, 3, 23, 40, 41, 41, 148400 },
+ 4, 23, 40, 41, 41, 148400 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
@@ -160,145 +159,144 @@ static const struct ath_rate_table ar5416_11ng_ratetable = {
{
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
- 0, 0, 1, 0, 0, 0, 0, 0 },
+ 0, 0, 0, 0, 0, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
- 1, 1, 1, 1, 1, 1, 1, 0 },
+ 1, 1, 1, 1, 1, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
- 2, 2, 2, 2, 2, 2, 2, 0 },
+ 2, 2, 2, 2, 2, 0 },
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
- 3, 3, 2, 3, 3, 3, 3, 0 },
+ 3, 3, 3, 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 4, 2, 1, 4, 4, 4, 4, 0 },
+ 4, 4, 4, 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 4, 3, 1, 5, 5, 5, 5, 0 },
+ 4, 5, 5, 5, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10100, 0x0a, 0x00, 24,
- 6, 4, 1, 6, 6, 6, 6, 0 },
+ 6, 6, 6, 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
14100, 0x0e, 0x00, 36,
- 6, 6, 2, 7, 7, 7, 7, 0 },
+ 6, 7, 7, 7, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17700, 0x09, 0x00, 48,
- 8, 10, 3, 8, 8, 8, 8, 0 },
+ 8, 8, 8, 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23700, 0x0d, 0x00, 72,
- 8, 14, 3, 9, 9, 9, 9, 0 },
+ 8, 9, 9, 9, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 8, 20, 3, 10, 10, 10, 10, 0 },
+ 8, 10, 10, 10, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
30900, 0x0c, 0x00, 108,
- 8, 23, 3, 11, 11, 11, 11, 0 },
+ 8, 11, 11, 11, 11, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
6400, 0x80, 0x00, 0,
- 4, 2, 3, 12, 28, 12, 28, 3216 },
+ 4, 12, 28, 12, 28, 3216 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
12700, 0x81, 0x00, 1,
- 6, 4, 3, 13, 29, 13, 29, 6434 },
+ 6, 13, 29, 13, 29, 6434 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
18800, 0x82, 0x00, 2,
- 6, 6, 3, 14, 30, 14, 30, 9650 },
+ 6, 14, 30, 14, 30, 9650 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
25000, 0x83, 0x00, 3,
- 8, 10, 3, 15, 31, 15, 31, 12868 },
+ 8, 15, 31, 15, 31, 12868 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
36700, 0x84, 0x00, 4,
- 8, 14, 3, 16, 32, 16, 32, 19304 },
+ 8, 16, 32, 16, 32, 19304 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
48100, 0x85, 0x00, 5,
- 8, 20, 3, 17, 33, 17, 33, 25740 },
+ 8, 17, 33, 17, 33, 25740 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
53500, 0x86, 0x00, 6,
- 8, 23, 3, 18, 34, 18, 34, 28956 },
+ 8, 18, 34, 18, 34, 28956 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
59000, 0x87, 0x00, 7,
- 8, 25, 3, 19, 35, 19, 36, 32180 },
+ 8, 19, 35, 19, 36, 32180 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
12700, 0x88, 0x00, 8,
- 4, 2, 3, 20, 37, 20, 37, 6430 },
+ 4, 20, 37, 20, 37, 6430 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
24800, 0x89, 0x00, 9,
- 6, 4, 3, 21, 38, 21, 38, 12860 },
+ 6, 21, 38, 21, 38, 12860 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
36600, 0x8a, 0x00, 10,
- 6, 6, 3, 22, 39, 22, 39, 19300 },
+ 6, 22, 39, 22, 39, 19300 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
48100, 0x8b, 0x00, 11,
- 8, 10, 3, 23, 40, 23, 40, 25736 },
+ 8, 23, 40, 23, 40, 25736 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
69500, 0x8c, 0x00, 12,
- 8, 14, 3, 24, 41, 24, 41, 38600 },
+ 8, 24, 41, 24, 41, 38600 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
89500, 0x8d, 0x00, 13,
- 8, 20, 3, 25, 42, 25, 42, 51472 },
+ 8, 25, 42, 25, 42, 51472 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
98900, 0x8e, 0x00, 14,
- 8, 23, 3, 26, 43, 26, 44, 57890 },
+ 8, 26, 43, 26, 44, 57890 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
108300, 0x8f, 0x00, 15,
- 8, 25, 3, 27, 44, 27, 45, 64320 },
+ 8, 27, 44, 27, 45, 64320 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
13200, 0x80, 0x00, 0,
- 8, 2, 3, 12, 28, 28, 28, 6684 },
+ 8, 12, 28, 28, 28, 6684 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
25900, 0x81, 0x00, 1,
- 8, 4, 3, 13, 29, 29, 29, 13368 },
+ 8, 13, 29, 29, 29, 13368 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
38600, 0x82, 0x00, 2,
- 8, 6, 3, 14, 30, 30, 30, 20052 },
+ 8, 14, 30, 30, 30, 20052 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
49800, 0x83, 0x00, 3,
- 8, 10, 3, 15, 31, 31, 31, 26738 },
+ 8, 15, 31, 31, 31, 26738 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
72200, 0x84, 0x00, 4,
- 8, 14, 3, 16, 32, 32, 32, 40104 },
+ 8, 16, 32, 32, 32, 40104 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
92900, 0x85, 0x00, 5,
- 8, 20, 3, 17, 33, 33, 33, 53476 },
+ 8, 17, 33, 33, 33, 53476 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
102700, 0x86, 0x00, 6,
- 8, 23, 3, 18, 34, 34, 34, 60156 },
+ 8, 18, 34, 34, 34, 60156 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
112000, 0x87, 0x00, 7,
- 8, 23, 3, 19, 35, 36, 36, 66840 },
+ 8, 19, 35, 36, 36, 66840 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
122000, 0x87, 0x00, 7,
- 8, 25, 3, 19, 35, 36, 36, 74200 },
+ 8, 19, 35, 36, 36, 74200 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
25800, 0x88, 0x00, 8,
- 8, 2, 3, 20, 37, 37, 37, 13360 },
+ 8, 20, 37, 37, 37, 13360 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
49800, 0x89, 0x00, 9,
- 8, 4, 3, 21, 38, 38, 38, 26720 },
+ 8, 21, 38, 38, 38, 26720 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
71900, 0x8a, 0x00, 10,
- 8, 6, 3, 22, 39, 39, 39, 40080 },
+ 8, 22, 39, 39, 39, 40080 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
92500, 0x8b, 0x00, 11,
- 8, 10, 3, 23, 40, 40, 40, 53440 },
+ 8, 23, 40, 40, 40, 53440 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
130300, 0x8c, 0x00, 12,
- 8, 14, 3, 24, 41, 41, 41, 80160 },
+ 8, 24, 41, 41, 41, 80160 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
162800, 0x8d, 0x00, 13,
- 8, 20, 3, 25, 42, 42, 42, 106880 },
+ 8, 25, 42, 42, 42, 106880 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
178200, 0x8e, 0x00, 14,
- 8, 23, 3, 26, 43, 43, 43, 120240 },
+ 8, 26, 43, 43, 43, 120240 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
192100, 0x8f, 0x00, 15,
- 8, 23, 3, 27, 44, 45, 45, 133600 },
+ 8, 27, 44, 45, 45, 133600 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
207000, 0x8f, 0x00, 15,
- 8, 25, 3, 27, 44, 45, 45, 148400 },
+ 8, 27, 44, 45, 45, 148400 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
};
@@ -307,31 +305,30 @@ static const struct ath_rate_table ar5416_11a_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, (0x80|12),
- 0, 2, 1, 0, 0 },
+ 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 0, 3, 1, 1, 0 },
+ 0, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, (0x80|24),
- 2, 4, 2, 2, 0 },
+ 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 2, 6, 2, 3, 0 },
+ 2, 3, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, (0x80|48),
- 4, 10, 3, 4, 0 },
+ 4, 4, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 4, 14, 3, 5, 0 },
+ 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 4, 19, 3, 6, 0 },
+ 4, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 4, 23, 3, 7, 0 },
+ 4, 7, 0 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
0, /* Phy rates allowed initially */
};
@@ -340,64 +337,42 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
{
{ VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
900, 0x1b, 0x00, 2,
- 0, 0, 1, 0, 0 },
+ 0, 0, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
1900, 0x1a, 0x04, 4,
- 1, 1, 1, 1, 0 },
+ 1, 1, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
4900, 0x19, 0x04, 11,
- 2, 2, 2, 2, 0 },
+ 2, 2, 0 },
{ VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
8100, 0x18, 0x04, 22,
- 3, 3, 2, 3, 0 },
+ 3, 3, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
5400, 0x0b, 0x00, 12,
- 4, 2, 1, 4, 0 },
+ 4, 4, 0 },
{ INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
7800, 0x0f, 0x00, 18,
- 4, 3, 1, 5, 0 },
+ 4, 5, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
10000, 0x0a, 0x00, 24,
- 6, 4, 1, 6, 0 },
+ 6, 6, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
13900, 0x0e, 0x00, 36,
- 6, 6, 2, 7, 0 },
+ 6, 7, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
17300, 0x09, 0x00, 48,
- 8, 10, 3, 8, 0 },
+ 8, 8, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
23000, 0x0d, 0x00, 72,
- 8, 14, 3, 9, 0 },
+ 8, 9, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
27400, 0x08, 0x00, 96,
- 8, 19, 3, 10, 0 },
+ 8, 10, 0 },
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 0x0c, 0x00, 108,
- 8, 23, 3, 11, 0 },
+ 8, 11, 0 },
},
50, /* probe interval */
- 50, /* rssi reduce interval */
- 0, /* Phy rates allowed initially */
-};
-
-static const struct ath_rate_table ar5416_11b_ratetable = {
- 4,
- {
- { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
- 900, 0x1b, 0x00, (0x80|2),
- 0, 0, 1, 0, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
- 1800, 0x1a, 0x04, (0x80|4),
- 1, 1, 1, 1, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
- 4300, 0x19, 0x04, (0x80|11),
- 1, 2, 2, 2, 0 },
- { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
- 7100, 0x18, 0x04, (0x80|22),
- 1, 4, 100, 3, 0 },
- },
- 100, /* probe interval */
- 100, /* rssi reduce interval */
0, /* Phy rates allowed initially */
};
@@ -454,13 +429,6 @@ static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv,
ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0;
}
-static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv,
- u8 index)
-{
- ASSERT(index <= ath_rc_priv->rate_table_size);
- return ath_rc_priv->valid_rate_index[index];
-}
-
static inline
int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
struct ath_rate_priv *ath_rc_priv,
@@ -501,9 +469,9 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
}
static inline int
-ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table,
- struct ath_rate_priv *ath_rc_priv,
- u8 cur_valid_txrate, u8 *next_idx)
+ath_rc_get_lower_rix(const struct ath_rate_table *rate_table,
+ struct ath_rate_priv *ath_rc_priv,
+ u8 cur_valid_txrate, u8 *next_idx)
{
int8_t i;
@@ -629,52 +597,20 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
return hi;
}
-static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- int *is_probing)
+/* Finds the highest rate index we can use */
+static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ const struct ath_rate_table *rate_table,
+ int *is_probing)
{
- u32 dt, best_thruput, this_thruput, now_msec;
+ u32 best_thruput, this_thruput, now_msec;
u8 rate, next_rate, best_rate, maxindex, minindex;
- int8_t rssi_last, rssi_reduce = 0, index = 0;
-
- *is_probing = 0;
-
- rssi_last = median(ath_rc_priv->rssi_last,
- ath_rc_priv->rssi_last_prev,
- ath_rc_priv->rssi_last_prev2);
-
- /*
- * Age (reduce) last ack rssi based on how old it is.
- * The bizarre numbers are so the delta is 160msec,
- * meaning we divide by 16.
- * 0msec <= dt <= 25msec: don't derate
- * 25msec <= dt <= 185msec: derate linearly from 0 to 10dB
- * 185msec <= dt: derate by 10dB
- */
+ int8_t index = 0;
now_msec = jiffies_to_msecs(jiffies);
- dt = now_msec - ath_rc_priv->rssi_time;
-
- if (dt >= 185)
- rssi_reduce = 10;
- else if (dt >= 25)
- rssi_reduce = (u8)((dt - 25) >> 4);
-
- /* Now reduce rssi_last by rssi_reduce */
- if (rssi_last < rssi_reduce)
- rssi_last = 0;
- else
- rssi_last -= rssi_reduce;
-
- /*
- * Now look up the rate in the rssi table and return it.
- * If no rates match then we return 0 (lowest rate)
- */
-
+ *is_probing = 0;
best_thruput = 0;
maxindex = ath_rc_priv->max_valid_rate-1;
-
minindex = 0;
best_rate = minindex;
@@ -700,7 +636,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
* 10-15 and we would be worse off then staying
* at the current rate.
*/
- per_thres = ath_rc_priv->state[rate].per;
+ per_thres = ath_rc_priv->per[rate];
if (per_thres < 12)
per_thres = 12;
@@ -714,7 +650,6 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
}
rate = best_rate;
- ath_rc_priv->rssi_last_lookup = rssi_last;
/*
* Must check the actual rate (ratekbps) to account for
@@ -741,10 +676,18 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc,
if (rate > (ath_rc_priv->rate_table_size - 1))
rate = ath_rc_priv->rate_table_size - 1;
- ASSERT((rate_table->info[rate].valid &&
- (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)) ||
- (rate_table->info[rate].valid_single_stream &&
- !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG)));
+ if (rate_table->info[rate].valid &&
+ (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG))
+ return rate;
+
+ if (rate_table->info[rate].valid_single_stream &&
+ !(ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG));
+ return rate;
+
+ /* This should not happen */
+ WARN_ON(1);
+
+ rate = ath_rc_priv->valid_rate_index[0];
return rate;
}
@@ -796,7 +739,6 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
* just CTS. Note that this is only done for OFDM/HT unicast frames.
*/
if ((sc->sc_flags & SC_OP_PROTECT_ENABLE) &&
- !(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
(rate_table->info[rix].phy == WLAN_RC_PHY_OFDM ||
WLAN_RC_PHY_HT(rate_table->info[rix].phy))) {
rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
@@ -806,50 +748,37 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
tx_info->control.rts_cts_rate_idx = cix;
}
-static u8 ath_rc_rate_getidx(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- const struct ath_rate_table *rate_table,
- u8 rix, u16 stepdown,
- u16 min_rate)
-{
- u32 j;
- u8 nextindex = 0;
-
- if (min_rate) {
- for (j = RATE_TABLE_SIZE; j > 0; j--) {
- if (ath_rc_get_nextlowervalid_txrate(rate_table,
- ath_rc_priv, rix, &nextindex))
- rix = nextindex;
- else
- break;
- }
- } else {
- for (j = stepdown; j > 0; j--) {
- if (ath_rc_get_nextlowervalid_txrate(rate_table,
- ath_rc_priv, rix, &nextindex))
- rix = nextindex;
- else
- break;
- }
- }
- return rix;
-}
-
-static void ath_rc_ratefind(struct ath_softc *sc,
- struct ath_rate_priv *ath_rc_priv,
- struct ieee80211_tx_rate_control *txrc)
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
{
+ struct ath_softc *sc = priv;
+ struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table;
struct sk_buff *skb = txrc->skb;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rates = tx_info->control.rates;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
- u8 try_per_rate = 0, i = 0, rix, nrix;
+ u8 try_per_rate, i = 0, rix, nrix;
int is_probe = 0;
+ if (rate_control_send_low(sta, priv_sta, txrc))
+ return;
+
+ /*
+ * For Multi Rate Retry we use a different number of
+ * retry attempt counts. This ends up looking like this:
+ *
+ * MRR[0] = 2
+ * MRR[1] = 2
+ * MRR[2] = 2
+ * MRR[3] = 4
+ *
+ */
+ try_per_rate = sc->hw->max_rate_tries;
+
rate_table = sc->cur_rate_table;
- rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, &is_probe);
+ rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe);
nrix = rix;
if (is_probe) {
@@ -858,18 +787,15 @@ static void ath_rc_ratefind(struct ath_softc *sc,
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
1, nrix, 0);
- try_per_rate = (ATH_11N_TXMAXTRY/4);
/* Get the next tried/allowed rate. No RTS for the next series
* after the probe rate
*/
- nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
- rate_table, nrix, 1, 0);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
} else {
- try_per_rate = (ATH_11N_TXMAXTRY/4);
/* Set the choosen rate. No RTS for first series entry. */
ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
try_per_rate, nrix, 0);
@@ -877,18 +803,14 @@ static void ath_rc_ratefind(struct ath_softc *sc,
/* Fill in the other rates for multirate retry */
for ( ; i < 4; i++) {
- u8 try_num;
- u8 min_rate;
-
- try_num = ((i + 1) == 4) ?
- ATH_11N_TXMAXTRY - (try_per_rate * i) : try_per_rate ;
- min_rate = (((i + 1) == 4) && 0);
+ /* Use twice the number of tries for the last MRR segment. */
+ if (i + 1 == 4)
+ try_per_rate = 4;
- nrix = ath_rc_rate_getidx(sc, ath_rc_priv,
- rate_table, nrix, 1, min_rate);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &nrix);
/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
- try_num, nrix, 1);
+ try_per_rate, nrix, 1);
}
/*
@@ -925,9 +847,8 @@ static void ath_rc_ratefind(struct ath_softc *sc,
*
* FIXME: Fix duration
*/
- if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (ieee80211_has_morefrags(fc) ||
- (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG))) {
+ if (ieee80211_has_morefrags(fc) ||
+ (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
rates[1].count = rates[2].count = rates[3].count = 0;
rates[1].idx = rates[2].idx = rates[3].idx = 0;
rates[0].count = ATH_TXMAXTRY;
@@ -960,13 +881,13 @@ static bool ath_rc_update_per(struct ath_softc *sc,
100 * 9 / 10
};
- last_per = ath_rc_priv->state[tx_rate].per;
+ last_per = ath_rc_priv->per[tx_rate];
if (xretries) {
if (xretries == 1) {
- ath_rc_priv->state[tx_rate].per += 30;
- if (ath_rc_priv->state[tx_rate].per > 100)
- ath_rc_priv->state[tx_rate].per = 100;
+ ath_rc_priv->per[tx_rate] += 30;
+ if (ath_rc_priv->per[tx_rate] > 100)
+ ath_rc_priv->per[tx_rate] = 100;
} else {
/* xretries == 2 */
count = ARRAY_SIZE(nretry_to_per_lookup);
@@ -974,7 +895,7 @@ static bool ath_rc_update_per(struct ath_softc *sc,
retries = count - 1;
/* new_PER = 7/8*old_PER + 1/8*(currentPER) */
- ath_rc_priv->state[tx_rate].per =
+ ath_rc_priv->per[tx_rate] =
(u8)(last_per - (last_per >> 3) + (100 >> 3));
}
@@ -1010,18 +931,14 @@ static bool ath_rc_update_per(struct ath_softc *sc,
n_frames = tx_info_priv->n_frames * (retries + 1);
cur_per = (100 * n_bad_frames / n_frames) >> 3;
new_per = (u8)(last_per - (last_per >> 3) + cur_per);
- ath_rc_priv->state[tx_rate].per = new_per;
+ ath_rc_priv->per[tx_rate] = new_per;
}
} else {
- ath_rc_priv->state[tx_rate].per =
+ ath_rc_priv->per[tx_rate] =
(u8)(last_per - (last_per >> 3) +
(nretry_to_per_lookup[retries] >> 3));
}
- ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev;
- ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last;
- ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi;
- ath_rc_priv->rssi_time = now_msec;
/*
* If we got at most one retry then increase the max rate if
@@ -1045,8 +962,8 @@ static bool ath_rc_update_per(struct ath_softc *sc,
ath_rc_priv->probe_rate;
probe_rate = ath_rc_priv->probe_rate;
- if (ath_rc_priv->state[probe_rate].per > 30)
- ath_rc_priv->state[probe_rate].per = 20;
+ if (ath_rc_priv->per[probe_rate] > 30)
+ ath_rc_priv->per[probe_rate] = 20;
ath_rc_priv->probe_rate = 0;
@@ -1065,18 +982,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
/*
* Don't update anything. We don't know if
* this was because of collisions or poor signal.
- *
- * Later: if rssi_ack is close to
- * ath_rc_priv->state[txRate].rssi_thres and we see lots
- * of retries, then we could increase
- * ath_rc_priv->state[txRate].rssi_thres.
*/
ath_rc_priv->hw_maxretry_pktcnt = 0;
} else {
- int32_t rssi_ackAvg;
- int8_t rssi_thres;
- int8_t rssi_ack_vmin;
-
/*
* It worked with no retries. First ignore bogus (small)
* rssi_ack values.
@@ -1086,43 +994,9 @@ static bool ath_rc_update_per(struct ath_softc *sc,
ath_rc_priv->hw_maxretry_pktcnt++;
}
- if (tx_info_priv->tx.ts_rssi <
- rate_table->info[tx_rate].rssi_ack_validmin)
- goto exit;
-
- /* Average the rssi */
- if (tx_rate != ath_rc_priv->rssi_sum_rate) {
- ath_rc_priv->rssi_sum_rate = tx_rate;
- ath_rc_priv->rssi_sum =
- ath_rc_priv->rssi_sum_cnt = 0;
- }
-
- ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi;
- ath_rc_priv->rssi_sum_cnt++;
-
- if (ath_rc_priv->rssi_sum_cnt < 4)
- goto exit;
-
- rssi_ackAvg =
- (ath_rc_priv->rssi_sum + 2) / 4;
- rssi_thres =
- ath_rc_priv->state[tx_rate].rssi_thres;
- rssi_ack_vmin =
- rate_table->info[tx_rate].rssi_ack_validmin;
-
- ath_rc_priv->rssi_sum =
- ath_rc_priv->rssi_sum_cnt = 0;
-
- /* Now reduce the current rssi threshold */
- if ((rssi_ackAvg < rssi_thres + 2) &&
- (rssi_thres > rssi_ack_vmin)) {
- ath_rc_priv->state[tx_rate].rssi_thres--;
- }
-
- state_change = true;
}
}
-exit:
+
return state_change;
}
@@ -1134,11 +1008,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
struct ath_tx_info_priv *tx_info_priv,
int tx_rate, int xretries, int retries)
{
-#define CHK_RSSI(rate) \
- ((ath_rc_priv->state[(rate)].rssi_thres + \
- rate_table->info[(rate)].rssi_ack_deltamin) > \
- ath_rc_priv->state[(rate)+1].rssi_thres)
-
u32 now_msec = jiffies_to_msecs(jiffies);
int rate;
u8 last_per;
@@ -1149,14 +1018,7 @@ static void ath_rc_update_ht(struct ath_softc *sc,
if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt))
return;
- /* To compensate for some imbalance between ctrl and ext. channel */
-
- if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy))
- tx_info_priv->tx.ts_rssi =
- tx_info_priv->tx.ts_rssi < 3 ? 0 :
- tx_info_priv->tx.ts_rssi - 3;
-
- last_per = ath_rc_priv->state[tx_rate].per;
+ last_per = ath_rc_priv->per[tx_rate];
/* Update PER first */
state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
@@ -1167,114 +1029,55 @@ static void ath_rc_update_ht(struct ath_softc *sc,
* If this rate looks bad (high PER) then stop using it for
* a while (except if we are probing).
*/
- if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 &&
+ if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 &&
rate_table->info[tx_rate].ratekbps <=
rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
- ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv,
- (u8)tx_rate, &ath_rc_priv->rate_max_phy);
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv,
+ (u8)tx_rate, &ath_rc_priv->rate_max_phy);
/* Don't probe for a little while. */
ath_rc_priv->probe_time = now_msec;
}
- if (state_change) {
- /*
- * Make sure the rates above this have higher rssi thresholds.
- * (Note: Monotonicity is kept within the OFDM rates and
- * within the CCK rates. However, no adjustment is
- * made to keep the rssi thresholds monotonically
- * increasing between the CCK and OFDM rates.)
- */
- for (rate = tx_rate; rate < size - 1; rate++) {
- if (rate_table->info[rate+1].phy !=
- rate_table->info[tx_rate].phy)
- break;
-
- if (CHK_RSSI(rate)) {
- ath_rc_priv->state[rate+1].rssi_thres =
- ath_rc_priv->state[rate].rssi_thres +
- rate_table->info[rate].rssi_ack_deltamin;
- }
- }
-
- /* Make sure the rates below this have lower rssi thresholds. */
- for (rate = tx_rate - 1; rate >= 0; rate--) {
- if (rate_table->info[rate].phy !=
- rate_table->info[tx_rate].phy)
- break;
-
- if (CHK_RSSI(rate)) {
- if (ath_rc_priv->state[rate+1].rssi_thres <
- rate_table->info[rate].rssi_ack_deltamin)
- ath_rc_priv->state[rate].rssi_thres = 0;
- else {
- ath_rc_priv->state[rate].rssi_thres =
- ath_rc_priv->state[rate+1].rssi_thres -
- rate_table->info[rate].rssi_ack_deltamin;
- }
-
- if (ath_rc_priv->state[rate].rssi_thres <
- rate_table->info[rate].rssi_ack_validmin) {
- ath_rc_priv->state[rate].rssi_thres =
- rate_table->info[rate].rssi_ack_validmin;
- }
- }
- }
- }
-
/* Make sure the rates below this have lower PER */
/* Monotonicity is kept only for rates below the current rate. */
- if (ath_rc_priv->state[tx_rate].per < last_per) {
+ if (ath_rc_priv->per[tx_rate] < last_per) {
for (rate = tx_rate - 1; rate >= 0; rate--) {
if (rate_table->info[rate].phy !=
rate_table->info[tx_rate].phy)
break;
- if (ath_rc_priv->state[rate].per >
- ath_rc_priv->state[rate+1].per) {
- ath_rc_priv->state[rate].per =
- ath_rc_priv->state[rate+1].per;
+ if (ath_rc_priv->per[rate] >
+ ath_rc_priv->per[rate+1]) {
+ ath_rc_priv->per[rate] =
+ ath_rc_priv->per[rate+1];
}
}
}
/* Maintain monotonicity for rates above the current rate */
for (rate = tx_rate; rate < size - 1; rate++) {
- if (ath_rc_priv->state[rate+1].per <
- ath_rc_priv->state[rate].per)
- ath_rc_priv->state[rate+1].per =
- ath_rc_priv->state[rate].per;
- }
-
- /* Every so often, we reduce the thresholds and
- * PER (different for CCK and OFDM). */
- if (now_msec - ath_rc_priv->rssi_down_time >=
- rate_table->rssi_reduce_interval) {
-
- for (rate = 0; rate < size; rate++) {
- if (ath_rc_priv->state[rate].rssi_thres >
- rate_table->info[rate].rssi_ack_validmin)
- ath_rc_priv->state[rate].rssi_thres -= 1;
- }
- ath_rc_priv->rssi_down_time = now_msec;
+ if (ath_rc_priv->per[rate+1] <
+ ath_rc_priv->per[rate])
+ ath_rc_priv->per[rate+1] =
+ ath_rc_priv->per[rate];
}
/* Every so often, we reduce the thresholds
* and PER (different for CCK and OFDM). */
if (now_msec - ath_rc_priv->per_down_time >=
- rate_table->rssi_reduce_interval) {
+ rate_table->probe_interval) {
for (rate = 0; rate < size; rate++) {
- ath_rc_priv->state[rate].per =
- 7 * ath_rc_priv->state[rate].per / 8;
+ ath_rc_priv->per[rate] =
+ 7 * ath_rc_priv->per[rate] / 8;
}
ath_rc_priv->per_down_time = now_msec;
}
ath_debug_stat_retries(sc, tx_rate, xretries, retries,
- ath_rc_priv->state[tx_rate].per);
+ ath_rc_priv->per[tx_rate]);
-#undef CHK_RSSI
}
static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
@@ -1410,9 +1213,7 @@ static void ath_rc_init(struct ath_softc *sc,
/* Initialize thresholds according to the global rate table */
for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
- ath_rc_priv->state[i].rssi_thres =
- rate_table->info[i].rssi_ack_validmin;
- ath_rc_priv->state[i].per = 0;
+ ath_rc_priv->per[i] = 0;
}
/* Determine the valid rates */
@@ -1521,7 +1322,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
/*
* If underrun error is seen assume it as an excessive retry only
* if prefetch trigger level have reached the max (0x3f for 5416)
- * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY
+ * Adjust the long retry as if the frame was tried hw->max_rate_tries
* times. This affects how ratectrl updates PER for the failed rate.
*/
if (tx_info_priv->tx.ts_flags &
@@ -1536,7 +1337,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
tx_status = 1;
ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
- (is_underrun) ? ATH_11N_TXMAXTRY :
+ (is_underrun) ? sc->hw->max_rate_tries :
tx_info_priv->tx.ts_longretry);
/* Check if aggregation has to be enabled for this tid */
@@ -1560,31 +1361,6 @@ exit:
kfree(tx_info_priv);
}
-static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
- struct ieee80211_tx_rate_control *txrc)
-{
- struct ieee80211_supported_band *sband = txrc->sband;
- struct sk_buff *skb = txrc->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_softc *sc = priv;
- struct ath_rate_priv *ath_rc_priv = priv_sta;
- __le16 fc = hdr->frame_control;
-
- /* lowest rate for management and NO_ACK frames */
- if (!ieee80211_is_data(fc) ||
- tx_info->flags & IEEE80211_TX_CTL_NO_ACK || !sta) {
- tx_info->control.rates[0].idx = rate_lowest_index(sband, sta);
- tx_info->control.rates[0].count =
- (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) ?
- 1 : ATH_MGT_TXMAXTRY;
- return;
- }
-
- /* Find tx rate for unicast frames */
- ath_rc_ratefind(sc, ath_rc_priv, txrc);
-}
-
static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
@@ -1697,7 +1473,6 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp
return NULL;
}
- rate_priv->rssi_down_time = jiffies_to_msecs(jiffies);
rate_priv->tx_triglevel_max = sc->sc_ah->caps.tx_triglevel_max;
return rate_priv;
@@ -1725,8 +1500,6 @@ static struct rate_control_ops ath_rate_ops = {
void ath_rate_attach(struct ath_softc *sc)
{
- sc->hw_rate_table[ATH9K_MODE_11B] =
- &ar5416_11b_ratetable;
sc->hw_rate_table[ATH9K_MODE_11A] =
&ar5416_11a_ratetable;
sc->hw_rate_table[ATH9K_MODE_11G] =
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index e3abd76103f..fa21a628ddd 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -112,8 +112,6 @@ struct ath_rate_table {
u8 short_preamble;
u8 dot11rate;
u8 ctrl_rate;
- int8_t rssi_ack_validmin;
- int8_t rssi_ack_deltamin;
u8 base_index;
u8 cw40index;
u8 sgi_index;
@@ -121,15 +119,9 @@ struct ath_rate_table {
u32 max_4ms_framelen;
} info[RATE_TABLE_SIZE];
u32 probe_interval;
- u32 rssi_reduce_interval;
u8 initial_ratemax;
};
-struct ath_tx_ratectrl_state {
- int8_t rssi_thres; /* required rssi for this rate (dB) */
- u8 per; /* recent estimate of packet error rate (%) */
-};
-
struct ath_rateset {
u8 rs_nrates;
u8 rs_rates[ATH_RATE_MAX];
@@ -138,22 +130,14 @@ struct ath_rateset {
/**
* struct ath_rate_priv - Rate Control priv data
* @state: RC state
- * @rssi_last: last ACK rssi
- * @rssi_last_lookup: last ACK rssi used for lookup
- * @rssi_last_prev: previous last ACK rssi
- * @rssi_last_prev2: 2nd previous last ACK rssi
- * @rssi_sum_cnt: count of rssi_sum for averaging
- * @rssi_sum_rate: rate that we are averaging
- * @rssi_sum: running sum of rssi for averaging
* @probe_rate: rate we are probing at
- * @rssi_time: msec timestamp for last ack rssi
- * @rssi_down_time: msec timestamp for last down step
* @probe_time: msec timestamp for last probe
* @hw_maxretry_pktcnt: num of packets since we got HW max retry error
* @max_valid_rate: maximum number of valid rate
* @per_down_time: msec timestamp for last PER down step
* @valid_phy_ratecnt: valid rate count
* @rate_max_phy: phy index for the max rate
+ * @per: PER for every valid rate in %
* @probe_interval: interval for ratectrl to probe for other rates
* @prev_data_rix: rate idx of last data frame
* @ht_cap: HT capabilities
@@ -161,13 +145,6 @@ struct ath_rateset {
* @neg_ht_rates: Negotiated HT rates
*/
struct ath_rate_priv {
- int8_t rssi_last;
- int8_t rssi_last_lookup;
- int8_t rssi_last_prev;
- int8_t rssi_last_prev2;
- int32_t rssi_sum_cnt;
- int32_t rssi_sum_rate;
- int32_t rssi_sum;
u8 rate_table_size;
u8 probe_rate;
u8 hw_maxretry_pktcnt;
@@ -177,14 +154,12 @@ struct ath_rate_priv {
u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX];
u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE];
u8 rate_max_phy;
- u32 rssi_time;
- u32 rssi_down_time;
+ u8 per[RATE_TABLE_SIZE];
u32 probe_time;
u32 per_down_time;
u32 probe_interval;
u32 prev_data_rix;
u32 tx_triglevel_max;
- struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE];
struct ath_rateset neg_rates;
struct ath_rateset neg_ht_rates;
struct ath_rate_softc *asc;
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index cece1c4c6bd..61edfab20ff 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -145,6 +145,10 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
u8 ratecode;
__le16 fc;
struct ieee80211_hw *hw;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ int last_rssi = ATH_RSSI_DUMMY_MARKER;
+
hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control;
@@ -229,17 +233,57 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
}
}
+ rcu_read_lock();
+ sta = ieee80211_find_sta(sc->hw, hdr->addr2);
+ if (sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ if (ds->ds_rxstat.rs_rssi != ATH9K_RSSI_BAD &&
+ !ds->ds_rxstat.rs_moreaggr)
+ ATH_RSSI_LPF(an->last_rssi, ds->ds_rxstat.rs_rssi);
+ last_rssi = an->last_rssi;
+ }
+ rcu_read_unlock();
+
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+ ds->ds_rxstat.rs_rssi = ATH_EP_RND(last_rssi,
+ ATH_RSSI_EP_MULTIPLIER);
+ if (ds->ds_rxstat.rs_rssi < 0)
+ ds->ds_rxstat.rs_rssi = 0;
+ else if (ds->ds_rxstat.rs_rssi > 127)
+ ds->ds_rxstat.rs_rssi = 127;
+
rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
rx_status->band = hw->conf.channel->band;
rx_status->freq = hw->conf.channel->center_freq;
rx_status->noise = sc->ani.noise_floor;
- rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
+ rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + ds->ds_rxstat.rs_rssi;
rx_status->antenna = ds->ds_rxstat.rs_antenna;
- /* at 45 you will be able to use MCS 15 reliably. A more elaborate
- * scheme can be used here but it requires tables of SNR/throughput for
- * each possible mode used. */
- rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+ /*
+ * Theory for reporting quality:
+ *
+ * At a hardware RSSI of 45 you will be able to use MCS 7 reliably.
+ * At a hardware RSSI of 45 you will be able to use MCS 15 reliably.
+ * At a hardware RSSI of 35 you should be able use 54 Mbps reliably.
+ *
+ * MCS 7 is the highets MCS index usable by a 1-stream device.
+ * MCS 15 is the highest MCS index usable by a 2-stream device.
+ *
+ * All ath9k devices are either 1-stream or 2-stream.
+ *
+ * How many bars you see is derived from the qual reporting.
+ *
+ * A more elaborate scheme can be used here but it requires tables
+ * of SNR/throughput for each possible mode used. For the MCS table
+ * you can refer to the wireless wiki:
+ *
+ * http://wireless.kernel.org/en/developers/Documentation/ieee80211/802.11n
+ *
+ */
+ if (conf_is_ht(&hw->conf))
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45;
+ else
+ rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 35;
/* rssi can be more than 45 though, anything above that
* should be considered at 100% */
@@ -505,11 +549,6 @@ static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
return false;
}
-static void ath_rx_ps_back_to_sleep(struct ath_softc *sc)
-{
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
-}
-
static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
{
struct ieee80211_mgmt *mgmt;
@@ -521,6 +560,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
if (memcmp(sc->curbssid, mgmt->bssid, ETH_ALEN) != 0)
return; /* not from our current AP */
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_BEACON;
+
if (sc->sc_flags & SC_OP_BEACON_SYNC) {
sc->sc_flags &= ~SC_OP_BEACON_SYNC;
DPRINTF(sc, ATH_DBG_PS, "Reconfigure Beacon timers based on "
@@ -528,14 +569,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
ath_beacon_config(sc, NULL);
}
- if (!(sc->hw->conf.flags & IEEE80211_CONF_PS)) {
- /* We are not in PS mode anymore; remain awake */
- DPRINTF(sc, ATH_DBG_PS, "Not in PS mode anymore, remain "
- "awake\n");
- sc->sc_flags &= ~(SC_OP_WAIT_FOR_BEACON | SC_OP_WAIT_FOR_CAB);
- return;
- }
-
if (ath_beacon_dtim_pending_cab(skb)) {
/*
* Remain awake waiting for buffered broadcast/multicast
@@ -556,11 +589,9 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
* fails to send a frame indicating that all CAB frames have
* been delivered.
*/
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
DPRINTF(sc, ATH_DBG_PS, "PS wait for CAB frames timed out\n");
}
-
- /* No more broadcast/multicast frames to be received at this point. */
- ath_rx_ps_back_to_sleep(sc);
}
static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
@@ -578,13 +609,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb)
ieee80211_is_action(hdr->frame_control)) &&
is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_moredata(hdr->frame_control)) {
- DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
- "sleep\n");
/*
* No more broadcast/multicast frames to be received at this
* point.
*/
- ath_rx_ps_back_to_sleep(sc);
+ sc->sc_flags &= ~SC_OP_WAIT_FOR_CAB;
+ DPRINTF(sc, ATH_DBG_PS, "All PS CAB frames received, back to "
+ "sleep\n");
} else if ((sc->sc_flags & SC_OP_WAIT_FOR_PSPOLL_DATA) &&
!is_multicast_ether_addr(hdr->addr1) &&
!ieee80211_has_morefrags(hdr->frame_control)) {
@@ -619,13 +650,18 @@ static void ath_rx_send_to_mac80211(struct ath_softc *sc, struct sk_buff *skb,
if (aphy == NULL)
continue;
nskb = skb_copy(skb, GFP_ATOMIC);
- if (nskb)
- __ieee80211_rx(aphy->hw, nskb, rx_status);
+ if (nskb) {
+ memcpy(IEEE80211_SKB_RXCB(nskb), rx_status,
+ sizeof(*rx_status));
+ ieee80211_rx(aphy->hw, nskb);
+ }
}
- __ieee80211_rx(sc->hw, skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx(sc->hw, skb);
} else {
/* Deliver unicast frames based on receiver address */
- __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx(ath_get_virt_hw(sc, hdr), skb);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 52605246679..8302aeb62e5 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -574,6 +574,7 @@
#define AR_D_GBL_IFS_SIFS 0x1030
#define AR_D_GBL_IFS_SIFS_M 0x0000FFFF
+#define AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR 0x000003AB
#define AR_D_GBL_IFS_SIFS_RESV0 0xFFFFFFFF
#define AR_D_TXBLK_BASE 0x1038
@@ -589,10 +590,12 @@
#define AR_D_GBL_IFS_SLOT 0x1070
#define AR_D_GBL_IFS_SLOT_M 0x0000FFFF
#define AR_D_GBL_IFS_SLOT_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR 0x00000420
#define AR_D_GBL_IFS_EIFS 0x10b0
#define AR_D_GBL_IFS_EIFS_M 0x0000FFFF
#define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000
+#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR 0x0000A5EB
#define AR_D_GBL_IFS_MISC 0x10f0
#define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007
@@ -738,6 +741,9 @@
#define AR_SREV_REVISION_9285_10 0
#define AR_SREV_REVISION_9285_11 1
#define AR_SREV_REVISION_9285_12 2
+#define AR_SREV_VERSION_9287 0x180
+#define AR_SREV_REVISION_9287_10 0
+#define AR_SREV_REVISION_9287_11 1
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -794,6 +800,21 @@
(AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
AR_SREV_REVISION_9285_12)))
+#define AR_SREV_9287(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9287))
+#define AR_SREV_9287_10(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_10))
+#define AR_SREV_9287_11(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9287_11))
+#define AR_SREV_9287_11_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_11)))
+
#define AR_RADIO_SREV_MAJOR 0xf0
#define AR_RAD5133_SREV_MAJOR 0xc0
#define AR_RAD2133_SREV_MAJOR 0xd0
@@ -809,6 +830,9 @@
#define AR_AHB_PAGE_SIZE_1K 0x00000000
#define AR_AHB_PAGE_SIZE_2K 0x00000008
#define AR_AHB_PAGE_SIZE_4K 0x00000010
+#define AR_AHB_CUSTOM_BURST_EN 0x000000C0
+#define AR_AHB_CUSTOM_BURST_EN_S 6
+#define AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL 3
#define AR_INTR_RTC_IRQ 0x00000001
#define AR_INTR_MAC_IRQ 0x00000002
@@ -885,6 +909,7 @@ enum {
#define AR_NUM_GPIO 14
#define AR928X_NUM_GPIO 10
#define AR9285_NUM_GPIO 12
+#define AR9287_NUM_GPIO 11
#define AR_GPIO_IN_OUT 0x4048
#define AR_GPIO_IN_VAL 0x0FFFC000
@@ -893,6 +918,8 @@ enum {
#define AR928X_GPIO_IN_VAL_S 10
#define AR9285_GPIO_IN_VAL 0x00FFF000
#define AR9285_GPIO_IN_VAL_S 12
+#define AR9287_GPIO_IN_VAL 0x003FF800
+#define AR9287_GPIO_IN_VAL_S 11
#define AR_GPIO_OE_OUT 0x404c
#define AR_GPIO_OE_OUT_DRV 0x3
@@ -1154,6 +1181,33 @@ enum {
#define AR9285_AN_TOP4 0x7870
#define AR9285_AN_TOP4_DEFAULT 0x10142c00
+#define AR9287_AN_RF2G3_CH0 0x7808
+#define AR9287_AN_RF2G3_CH1 0x785c
+#define AR9287_AN_RF2G3_DB1 0xE0000000
+#define AR9287_AN_RF2G3_DB1_S 29
+#define AR9287_AN_RF2G3_DB2 0x1C000000
+#define AR9287_AN_RF2G3_DB2_S 26
+#define AR9287_AN_RF2G3_OB_CCK 0x03800000
+#define AR9287_AN_RF2G3_OB_CCK_S 23
+#define AR9287_AN_RF2G3_OB_PSK 0x00700000
+#define AR9287_AN_RF2G3_OB_PSK_S 20
+#define AR9287_AN_RF2G3_OB_QAM 0x000E0000
+#define AR9287_AN_RF2G3_OB_QAM_S 17
+#define AR9287_AN_RF2G3_OB_PAL_OFF 0x0001C000
+#define AR9287_AN_RF2G3_OB_PAL_OFF_S 14
+
+#define AR9287_AN_TXPC0 0x7898
+#define AR9287_AN_TXPC0_TXPCMODE 0x0000C000
+#define AR9287_AN_TXPC0_TXPCMODE_S 14
+#define AR9287_AN_TXPC0_TXPCMODE_NORMAL 0
+#define AR9287_AN_TXPC0_TXPCMODE_TEST 1
+#define AR9287_AN_TXPC0_TXPCMODE_TEMPSENSE 2
+#define AR9287_AN_TXPC0_TXPCMODE_ATBTEST 3
+
+#define AR9287_AN_TOP2 0x78b4
+#define AR9287_AN_TOP2_XPABIAS_LVL 0xC0000000
+#define AR9287_AN_TOP2_XPABIAS_LVL_S 30
+
#define AR_STA_ID0 0x8000
#define AR_STA_ID1 0x8004
#define AR_STA_ID1_SADH_MASK 0x0000FFFF
@@ -1188,6 +1242,7 @@ enum {
#define AR_TIME_OUT_ACK_S 0
#define AR_TIME_OUT_CTS 0x3FFF0000
#define AR_TIME_OUT_CTS_S 16
+#define AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR 0x16001D56
#define AR_RSSI_THR 0x8018
#define AR_RSSI_THR_MASK 0x000000FF
@@ -1203,6 +1258,7 @@ enum {
#define AR_USEC_TX_LAT_S 14
#define AR_USEC_RX_LAT 0x1F800000
#define AR_USEC_RX_LAT_S 23
+#define AR_USEC_ASYNC_FIFO_DUR 0x12e00074
#define AR_RESET_TSF 0x8020
#define AR_RESET_TSF_ONCE 0x01000000
@@ -1468,6 +1524,10 @@ enum {
#define AR_SLP_MIB_CLEAR 0x00000001
#define AR_SLP_MIB_PENDING 0x00000002
+#define AR_MAC_PCU_LOGIC_ANALYZER 0x8264
+#define AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768 0x20000000
+
+
#define AR_2040_MODE 0x8318
#define AR_2040_JOINED_RX_CLEAR 0x00000001
@@ -1485,6 +1545,39 @@ enum {
#define AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE 0x00000002
#define AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT 0x00000004
+#define AR_PCU_MISC_MODE2_RESERVED 0x00000038
+#define AR_PCU_MISC_MODE2_ADHOC_MCAST_KEYID_ENABLE 0x00000040
+#define AR_PCU_MISC_MODE2_CFP_IGNORE 0x00000080
+#define AR_PCU_MISC_MODE2_MGMT_QOS 0x0000FF00
+#define AR_PCU_MISC_MODE2_MGMT_QOS_S 8
+#define AR_PCU_MISC_MODE2_ENABLE_LOAD_NAV_BEACON_DURATION 0x00010000
+#define AR_PCU_MISC_MODE2_ENABLE_AGGWEP 0x00020000
+#define AR_PCU_MISC_MODE2_HWWAR1 0x00100000
+#define AR_PCU_MISC_MODE2_HWWAR2 0x02000000
+#define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000
+
+#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400
+#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000
+
+
+#define AR_AES_MUTE_MASK0 0x805c
+#define AR_AES_MUTE_MASK0_FC 0x0000FFFF
+#define AR_AES_MUTE_MASK0_QOS 0xFFFF0000
+#define AR_AES_MUTE_MASK0_QOS_S 16
+
+#define AR_AES_MUTE_MASK1 0x8060
+#define AR_AES_MUTE_MASK1_SEQ 0x0000FFFF
+#define AR_AES_MUTE_MASK1_SEQ_S 0
+#define AR_AES_MUTE_MASK1_FC_MGMT 0xFFFF0000
+#define AR_AES_MUTE_MASK1_FC_MGMT_S 16
+
+#define AR_RATE_DURATION_0 0x8700
+#define AR_RATE_DURATION_31 0x87CC
+#define AR_RATE_DURATION_32 0x8780
+#define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2))
+
+
#define AR_KEYTABLE_0 0x8800
#define AR_KEYTABLE(_n) (AR_KEYTABLE_0 + ((_n)*32))
#define AR_KEY_CACHE_SIZE 128
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index 1ff429b027d..e1d419e02b4 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -660,3 +660,20 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
sc->wiphy_scheduler_int);
}
+
+/* caller must hold wiphy_lock */
+bool ath9k_all_wiphys_idle(struct ath_softc *sc)
+{
+ unsigned int i;
+ if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+ return false;
+ }
+ for (i = 0; i < sc->num_sec_wiphy; i++) {
+ struct ath_wiphy *aphy = sc->sec_wiphy[i];
+ if (!aphy)
+ continue;
+ if (aphy->state != ATH_WIPHY_INACTIVE)
+ return false;
+ }
+ return true;
+}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 4ccf48e396d..4ff155e8ee5 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -73,18 +73,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
/* Aggregation logic */
/*********************/
-static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno)
-{
- struct ath_atx_tid *tid;
- tid = ATH_AN_2_TID(an, tidno);
-
- if (tid->state & AGGR_ADDBA_COMPLETE ||
- tid->state & AGGR_ADDBA_PROGRESS)
- return 1;
- else
- return 0;
-}
-
static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
{
struct ath_atx_ac *ac = tid->ac;
@@ -250,7 +238,10 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
struct ath_buf *tbf;
spin_lock_bh(&sc->tx.txbuflock);
- ASSERT(!list_empty((&sc->tx.txbuf)));
+ if (WARN_ON(list_empty(&sc->tx.txbuf))) {
+ spin_unlock_bh(&sc->tx.txbuflock);
+ return NULL;
+ }
tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
list_del(&tbf->list);
spin_unlock_bh(&sc->tx.txbuflock);
@@ -391,6 +382,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *tbf;
tbf = ath_clone_txbuf(sc, bf_last);
+ /*
+ * Update tx baw and complete the frame with
+ * failed status if we run out of tx buf
+ */
+ if (!tbf) {
+ spin_lock_bh(&txq->axq_lock);
+ ath_tx_update_baw(sc, tid,
+ bf->bf_seqno);
+ spin_unlock_bh(&txq->axq_lock);
+
+ bf->bf_state.bf_type |= BUF_XRETRY;
+ ath_tx_rc_status(bf, ds, nbad,
+ 0, false);
+ ath_tx_complete_buf(sc, bf, &bf_head,
+ 0, 0);
+ break;
+ }
+
ath9k_hw_cleartxdesc(sc->sc_ah, tbf->bf_desc);
list_add_tail(&tbf->list, &bf_head);
} else {
@@ -414,7 +423,6 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
if (tid->state & AGGR_CLEANUP) {
if (tid->baw_head == tid->baw_tail) {
tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->addba_exchangeattempts = 0;
tid->state &= ~AGGR_CLEANUP;
/* send buffered frames as singles */
@@ -719,7 +727,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
txtid->state &= ~AGGR_ADDBA_PROGRESS;
- txtid->addba_exchangeattempts = 0;
return 0;
}
@@ -747,7 +754,6 @@ int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
txtid->state |= AGGR_CLEANUP;
} else {
txtid->state &= ~AGGR_ADDBA_COMPLETE;
- txtid->addba_exchangeattempts = 0;
ath_tx_flush_tid(sc, txtid);
}
@@ -780,14 +786,8 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
txtid = ATH_AN_2_TID(an, tidno);
- if (!(txtid->state & AGGR_ADDBA_COMPLETE)) {
- if (!(txtid->state & AGGR_ADDBA_PROGRESS) &&
- (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) {
- txtid->addba_exchangeattempts++;
+ if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
return true;
- }
- }
-
return false;
}
@@ -872,6 +872,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
txq->axq_aggr_depth = 0;
txq->axq_totalqueued = 0;
txq->axq_linkbuf = NULL;
+ txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum;
}
return &sc->tx.txq[qnum];
@@ -1038,6 +1039,10 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
ath_tx_complete_buf(sc, bf, &bf_head, 0, 0);
}
+ spin_lock_bh(&txq->axq_lock);
+ txq->axq_tx_inprogress = false;
+ spin_unlock_bh(&txq->axq_lock);
+
/* flush any pending frames if aggregation is enabled */
if (sc->sc_flags & SC_OP_TXAGGR) {
if (!retry_tx) {
@@ -1118,8 +1123,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
if (tid->paused)
continue;
- if ((txq->axq_depth % 2) == 0)
- ath_tx_sched_aggr(sc, txq, tid);
+ ath_tx_sched_aggr(sc, txq, tid);
/*
* add tid to round-robin queue if more frames
@@ -1636,7 +1640,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
goto tx_done;
}
- if (ath_aggr_query(sc, an, bf->bf_tidno)) {
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
/*
* Try aggregation if it's a unicast data frame
* and the destination is HT capable.
@@ -1962,19 +1966,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
if (bf->bf_stale) {
bf_held = bf;
if (list_is_last(&bf_held->list, &txq->axq_q)) {
- txq->axq_link = NULL;
- txq->axq_linkbuf = NULL;
spin_unlock_bh(&txq->axq_lock);
-
- /*
- * The holding descriptor is the last
- * descriptor in queue. It's safe to remove
- * the last holding descriptor in BH context.
- */
- spin_lock_bh(&sc->tx.txbuflock);
- list_move_tail(&bf_held->list, &sc->tx.txbuf);
- spin_unlock_bh(&sc->tx.txbuflock);
-
break;
} else {
bf = list_entry(bf_held->list.next,
@@ -2011,6 +2003,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
txq->axq_aggr_depth--;
txok = (ds->ds_txstat.ts_status == 0);
+ txq->axq_tx_inprogress = false;
spin_unlock_bh(&txq->axq_lock);
if (bf_held) {
@@ -2044,6 +2037,40 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
}
}
+void ath_tx_complete_poll_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ tx_complete_work.work);
+ struct ath_txq *txq;
+ int i;
+ bool needreset = false;
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+ if (ATH_TXQ_SETUP(sc, i)) {
+ txq = &sc->tx.txq[i];
+ spin_lock_bh(&txq->axq_lock);
+ if (txq->axq_depth) {
+ if (txq->axq_tx_inprogress) {
+ needreset = true;
+ spin_unlock_bh(&txq->axq_lock);
+ break;
+ } else {
+ txq->axq_tx_inprogress = true;
+ }
+ }
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
+ if (needreset) {
+ DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+ ath_reset(sc, false);
+ }
+
+ queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work,
+ msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
+}
+
+
void ath_tx_tasklet(struct ath_softc *sc)
{
@@ -2084,6 +2111,8 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
goto err;
}
+ INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
+
err:
if (error != 0)
ath_tx_cleanup(sc);
@@ -2122,7 +2151,6 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
tid->ac = &an->ac[acno];
tid->state &= ~AGGR_ADDBA_COMPLETE;
tid->state &= ~AGGR_ADDBA_PROGRESS;
- tid->addba_exchangeattempts = 0;
}
for (acno = 0, ac = &an->ac[acno];
@@ -2179,7 +2207,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
tid->sched = false;
ath_tid_drain(sc, txq, tid);
tid->state &= ~AGGR_ADDBA_COMPLETE;
- tid->addba_exchangeattempts = 0;
tid->state &= ~AGGR_CLEANUP;
}
}
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index bf3d25ba7be..077bcc142cd 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -586,7 +586,5 @@ u32 ath_regd_get_band_ctl(struct ath_regulatory *reg,
default:
return NO_CTL;
}
-
- return NO_CTL;
}
EXPORT_SYMBOL(ath_regd_get_band_ctl);
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 291a94bd46f..05813bc3e30 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -793,13 +793,13 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
!(*priv->present_callback)(priv->card)) {
dev->stats.tx_errors++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (priv->station_state != STATION_STATE_READY) {
dev->stats.tx_errors++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* first ensure the timer func cannot run */
@@ -856,7 +856,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_bh(&priv->timerlock);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void atmel_transmit_management_frame(struct atmel_private *priv,
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e71c8d9cd70..3f4360ad0e4 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev)
static void b43_dump_keymemory(struct b43_wldev *dev)
{
unsigned int i, index, offset;
- DECLARE_MAC_BUF(macbuf);
u8 mac[ETH_ALEN];
u16 algo;
u32 rcmta0;
@@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
((index - 4) * 2) + 1);
*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
- printk(" MAC: %s",
- print_mac(macbuf, mac));
+ printk(" MAC: %pM", mac);
} else
printk(" DEFAULT KEY");
printk("\n");
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index 55f36a7254d..5b85e7d7359 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -670,7 +670,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
goto drop;
}
- ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(dev->wl->hw, skb);
return;
drop:
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
index b8e39dd06e9..f79cee82601 100644
--- a/drivers/net/wireless/b43legacy/xmit.c
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -591,7 +591,8 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
}
dev->stats.last_rx = jiffies;
- ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(dev->wl->hw, skb);
return;
drop:
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index d313b005114..1fe1bbabb90 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -75,7 +75,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (local->ddev != dev) {
@@ -89,14 +89,14 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
"AP device with Ethernet net dev\n", dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
} else {
if (local->iw_mode == IW_MODE_REPEAT) {
printk(KERN_DEBUG "%s: prism2_tx: trying to use "
"non-WDS link in Repeater mode\n", dev->name);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} else if (local->iw_mode == IW_MODE_INFRA &&
(local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
memcmp(skb->data + ETH_ALEN, dev->dev_addr,
@@ -210,13 +210,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (pskb_expand_head(skb, need_headroom, need_tailroom,
GFP_ATOMIC)) {
kfree_skb(skb);
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
} else if (skb_headroom(skb) < need_headroom) {
struct sk_buff *tmp = skb;
@@ -224,13 +224,13 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(tmp);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
} else {
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL) {
iface->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
}
@@ -256,7 +256,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb->dev = local->dev;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -276,7 +276,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
iface->stats.tx_packets++;
@@ -301,7 +301,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Send IEEE 802.11 encapsulated frame using the master radio device */
skb->dev = local->dev;
dev_queue_xmit(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -396,7 +396,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
"expected 0x%08x)\n",
dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
@@ -414,7 +414,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < 24) {
printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
"(len=%d)\n", dev->name, skb->len);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
@@ -441,13 +441,13 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, meta->ethertype);
hostap_dump_tx_80211(dev->name, skb);
- ret = 0; /* drop packet */
+ ret = NETDEV_TX_OK; /* drop packet */
iface->stats.tx_dropped++;
goto fail;
}
break;
case AP_TX_DROP:
- ret = 0; /* drop packet */
+ ret = NETDEV_TX_OK; /* drop packet */
iface->stats.tx_dropped++;
goto fail;
case AP_TX_RETRY:
@@ -455,7 +455,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
case AP_TX_BUFFERED:
/* do not free skb here, it will be freed when the
* buffered frame is sent/timed out */
- ret = 0;
+ ret = NETDEV_TX_OK;
goto tx_exit;
}
@@ -501,7 +501,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
"frame (drop_unencrypted=1)\n", dev->name);
}
iface->stats.tx_dropped++;
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
@@ -510,7 +510,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb == NULL) {
printk(KERN_DEBUG "%s: TX - encryption failed\n",
dev->name);
- ret = 0;
+ ret = NETDEV_TX_OK;
goto fail;
}
meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -519,23 +519,23 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
"expected 0x%08x) after hostap_tx_encrypt\n",
dev->name, meta->magic,
HOSTAP_SKB_TX_DATA_MAGIC);
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
goto fail;
}
}
if (local->func->tx == NULL || local->func->tx(skb, dev)) {
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_dropped++;
} else {
- ret = 0;
+ ret = NETDEV_TX_OK;
iface->stats.tx_packets++;
iface->stats.tx_bytes += skb->len;
}
fail:
- if (!ret && skb)
+ if (ret == NETDEV_TX_OK && skb)
dev_kfree_skb(skb);
tx_exit:
if (tx.sta_ptr)
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 63374027735..ad8eab4a639 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -666,7 +666,8 @@ static int prism2_config(struct pcmcia_device *link)
* irq structure is initialized.
*/
if (link->conf.Attributes & CONF_ENABLE_IRQ) {
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING |
+ IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = prism2_interrupt;
link->irq.Instance = dev;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 44c29b3f672..2dc1cdbb493 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -7250,9 +7250,6 @@ static void ipw_bg_qos_activate(struct work_struct *work)
struct ipw_priv *priv =
container_of(work, struct ipw_priv, qos_activate);
- if (priv == NULL)
- return;
-
mutex_lock(&priv->mutex);
if (priv->status & STATUS_ASSOCIATED)
@@ -11436,11 +11433,11 @@ static struct pci_device_id card_ids[] = {
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
{PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */
- {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
- {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */
+ {PCI_VDEVICE(INTEL, 0x104f), 0},
+ {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */
+ {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */
+ {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */
+ {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */
/* required last entry */
{0,}
diff --git a/drivers/net/wireless/ipw2x00/libipw_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c
index da2ad5437ce..2e8f84fb29f 100644
--- a/drivers/net/wireless/ipw2x00/libipw_tx.c
+++ b/drivers/net/wireless/ipw2x00/libipw_tx.c
@@ -527,13 +527,13 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
if (ret == 0) {
dev->stats.tx_packets++;
dev->stats.tx_bytes += txb->payload_size;
- return 0;
+ return NETDEV_TX_OK;
}
ieee80211_txb_free(txb);
}
- return 0;
+ return NETDEV_TX_OK;
failed:
spin_unlock_irqrestore(&ieee->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 7da52f1cc1d..a899be914eb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -46,7 +46,7 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 2
+#define IWL1000_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL1000_UCODE_API_MIN 1
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 73f93a0ff2d..b569c6f38e5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -232,9 +232,8 @@ struct iwl3945_eeprom {
#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */
#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */
-#define TFD_QUEUE_MIN 0
-#define TFD_QUEUE_MAX 5 /* 4 DATA + 1 CMD */
-
+/* 4 DATA + 1 CMD. There are 2 HCCA queues that are not used. */
+#define IWL39_NUM_QUEUES 5
#define IWL_NUM_SCAN_RATES (2)
#define IWL_DEFAULT_TX_RETRY 15
@@ -280,8 +279,6 @@ struct iwl3945_eeprom {
/* Size of uCode instruction memory in bootstrap state machine */
#define IWL39_MAX_BSM_SIZE IWL39_RTC_INST_SIZE
-#define IWL39_MAX_NUM_QUEUES 8
-
static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
{
return (addr >= IWL39_RTC_DATA_LOWER_BOUND) &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index 5eb538d18a8..a16bd4147ea 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -673,33 +673,17 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
s8 scale_action = 0;
unsigned long flags;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc;
- u16 rate_mask = 0;
+ u16 rate_mask = sta ? sta->supp_rates[sband->band] : 0;
s8 max_rate_idx = -1;
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
IWL_DEBUG_RATE(priv, "enter\n");
- if (sta)
- rate_mask = sta->supp_rates[sband->band];
-
- /* Send management frames and NO_ACK data using lowest rate. */
- fc = le16_to_cpu(hdr->frame_control);
- if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
- info->flags & IEEE80211_TX_CTL_NO_ACK ||
- !sta || !priv_sta) {
- IWL_DEBUG_RATE(priv, "leave: No STA priv data to update!\n");
- if (!rate_mask)
- info->control.rates[0].idx =
- rate_lowest_index(sband, NULL);
- else
- info->control.rates[0].idx =
- rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
+
+ rate_mask = sta->supp_rates[sband->band];
/* get user max rate if set */
max_rate_idx = txrc->max_rate_idx;
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 46288e72488..8ee403cd9b9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -502,14 +502,14 @@ static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
}
}
if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
+ iwl_print_hex_dump(IWL_DL_RX, data, length);
}
static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
struct iwl_rx_packet *pkt,
struct ieee80211_hdr *header, int group100)
{
- if (priv->debug_level & IWL_DL_RX)
+ if (iwl_debug_level & IWL_DL_RX)
_iwl3945_dbg_report_frame(priv, pkt, header, group100);
}
@@ -577,7 +577,8 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
if (ieee80211_is_data(hdr->frame_control))
priv->rxtxpackets += len;
#endif
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb);
rxb->skb = NULL;
}
@@ -962,7 +963,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
goto error;
/* Tx queue(s) */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
@@ -1139,7 +1140,7 @@ void iwl3945_hw_txq_ctx_free(struct iwl_priv *priv)
int txq_id;
/* Tx queues */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++)
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
if (txq_id == IWL_CMD_QUEUE_NUM)
iwl_cmd_queue_free(priv);
else
@@ -1155,7 +1156,7 @@ void iwl3945_hw_txq_ctx_stop(struct iwl_priv *priv)
iwl_write_prph(priv, ALM_SCD_MODE_REG, 0);
/* reset TFD queues */
- for (txq_id = 0; txq_id <= priv->hw_params.max_txq_num; txq_id++) {
+ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
iwl_write_direct32(priv, FH39_TCSR_CONFIG(txq_id), 0x0);
iwl_poll_direct_bit(priv, FH39_TSSR_TX_STATUS,
FH39_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(txq_id),
@@ -1986,7 +1987,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
staging_rxon->reserved4 = 0;
staging_rxon->reserved5 = 0;
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, !iwl3945_mod_params.sw_crypto);
/* Apply the new configuration */
rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
@@ -2551,7 +2552,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
}
/* Assign number of Usable TX queues */
- priv->hw_params.max_txq_num = TFD_QUEUE_MAX;
+ priv->hw_params.max_txq_num = IWL39_NUM_QUEUES;
priv->hw_params.tfd_size = sizeof(struct iwl3945_tfd);
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_3K;
@@ -2562,6 +2563,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.bcast_sta_id = IWL3945_BROADCAST_ID;
priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
+ priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
return 0;
}
@@ -2784,11 +2786,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
return 0;
}
+#define IWL3945_UCODE_GET(item) \
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL3945_UCODE_GET(inst_size);
+IWL3945_UCODE_GET(data_size);
+IWL3945_UCODE_GET(init_size);
+IWL3945_UCODE_GET(init_data_size);
+IWL3945_UCODE_GET(boot_size);
+
static struct iwl_hcmd_ops iwl3945_hcmd = {
.rxon_assoc = iwl3945_send_rxon_assoc,
.commit_rxon = iwl3945_commit_rxon,
};
+static struct iwl_ucode_ops iwl3945_ucode = {
+ .get_header_size = iwl3945_ucode_get_header_size,
+ .get_build = iwl3945_ucode_get_build,
+ .get_inst_size = iwl3945_ucode_get_inst_size,
+ .get_data_size = iwl3945_ucode_get_data_size,
+ .get_init_size = iwl3945_ucode_get_init_size,
+ .get_init_data_size = iwl3945_ucode_get_init_data_size,
+ .get_boot_size = iwl3945_ucode_get_boot_size,
+ .get_data = iwl3945_ucode_get_data,
+};
+
static struct iwl_lib_ops iwl3945_lib = {
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2829,6 +2870,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
};
static struct iwl_ops iwl3945_ops = {
+ .ucode = &iwl3945_ucode,
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 2de6471d4be..f2ffc48cbaf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -111,9 +111,6 @@ enum iwl3945_antenna {
#define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL39_MIN_NUM_QUEUES 4
-
#define IEEE80211_DATA_LEN 2304
#define IEEE80211_4ADDR_LEN 30
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 8f3d4bc6a03..c30a1b96057 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -146,7 +146,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Begin load bsm\n");
- priv->ucode_type = UCODE_RT;
+ priv->ucode_type = UCODE_INIT;
/* make sure bootstrap program is no larger than BSM's SRAM size */
if (len > IWL49_MAX_BSM_SIZE)
@@ -256,6 +256,8 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
*/
static void iwl4965_init_alive_start(struct iwl_priv *priv)
{
+ int ret;
+
/* Check alive response for "valid" sign from uCode */
if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
/* We had an error bringing up the hardware, so take it
@@ -287,6 +289,28 @@ static void iwl4965_init_alive_start(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "Couldn't set up uCode pointers.\n");
goto restart;
}
+ priv->ucode_type = UCODE_RT;
+ if (test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+ IWL_WARN(priv, "Runtime uCode already alive? "
+ "Waiting for alive anyway\n");
+ clear_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+ }
+ ret = wait_event_interruptible_timeout(
+ priv->wait_command_queue,
+ test_bit(STATUS_RT_UCODE_ALIVE, &priv->status),
+ UCODE_ALIVE_TIMEOUT);
+ if (!ret) {
+ /* FIXME: if STATUS_RT_UCODE_ALIVE timeout
+ * go back to restart the download Init uCode again
+ * this might cause to trap in the restart loop
+ */
+ priv->ucode_type = UCODE_NONE;
+ if (!test_bit(STATUS_RT_UCODE_ALIVE, &priv->status)) {
+ IWL_ERR(priv, "Runtime timeout after %dms\n",
+ jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+ goto restart;
+ }
+ }
return;
restart:
@@ -728,7 +752,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv)
static struct iwl_sensitivity_ranges iwl4965_sensitivity = {
.min_nrg_cck = 97,
- .max_nrg_cck = 0,
+ .max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 85,
.auto_corr_min_ofdm_mrc = 170,
@@ -2221,12 +2245,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
cancel_work_sync(&priv->txpower_work);
}
+#define IWL4965_UCODE_GET(item) \
+static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl4965_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL4965_UCODE_GET(inst_size);
+IWL4965_UCODE_GET(data_size);
+IWL4965_UCODE_GET(init_size);
+IWL4965_UCODE_GET(init_data_size);
+IWL4965_UCODE_GET(boot_size);
+
static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
.set_rxon_chain = iwl_set_rxon_chain,
};
+static struct iwl_ucode_ops iwl4965_ucode = {
+ .get_header_size = iwl4965_ucode_get_header_size,
+ .get_build = iwl4965_ucode_get_build,
+ .get_inst_size = iwl4965_ucode_get_inst_size,
+ .get_data_size = iwl4965_ucode_get_data_size,
+ .get_init_size = iwl4965_ucode_get_init_size,
+ .get_init_data_size = iwl4965_ucode_get_init_data_size,
+ .get_boot_size = iwl4965_ucode_get_boot_size,
+ .get_data = iwl4965_ucode_get_data,
+};
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.get_hcmd_size = iwl4965_get_hcmd_size,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2287,6 +2349,7 @@ static struct iwl_lib_ops iwl4965_lib = {
};
static struct iwl_ops iwl4965_ops = {
+ .ucode = &iwl4965_ucode,
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
@@ -2313,8 +2376,6 @@ module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444);
MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(debug, iwl4965_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
module_param_named(
disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index b3c648ce8c7..702db07fa38 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
+ /* Setting digital SVR for 1000 card to 1.32V */
+ iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
+ APMG_SVR_DIGITAL_VOLTAGE_1_32,
+ ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+ }
+
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -388,7 +395,7 @@ void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.min_nrg_cck = 95,
- .max_nrg_cck = 0,
+ .max_nrg_cck = 0, /* not used, set to 0 */
.auto_corr_min_ofdm = 90,
.auto_corr_min_ofdm_mrc = 170,
.auto_corr_min_ofdm_x1 = 120,
@@ -407,6 +414,28 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = {
.nrg_th_ofdm = 95,
};
+static struct iwl_sensitivity_ranges iwl5150_sensitivity = {
+ .min_nrg_cck = 95,
+ .max_nrg_cck = 0, /* not used, set to 0 */
+ .auto_corr_min_ofdm = 90,
+ .auto_corr_min_ofdm_mrc = 170,
+ .auto_corr_min_ofdm_x1 = 105,
+ .auto_corr_min_ofdm_mrc_x1 = 220,
+
+ .auto_corr_max_ofdm = 120,
+ .auto_corr_max_ofdm_mrc = 210,
+ /* max = min for performance bug in 5150 DSP */
+ .auto_corr_max_ofdm_x1 = 105,
+ .auto_corr_max_ofdm_mrc_x1 = 220,
+
+ .auto_corr_min_cck = 125,
+ .auto_corr_max_cck = 200,
+ .auto_corr_min_cck_mrc = 170,
+ .auto_corr_max_cck_mrc = 400,
+ .nrg_th_cck = 95,
+ .nrg_th_ofdm = 95,
+};
+
static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv,
size_t offset)
{
@@ -826,8 +855,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IEEE80211_BAND_5GHZ);
priv->hw_params.rx_wrt_ptr_reg = FH_RSCSR_CHNL0_WPTR;
- priv->hw_params.sens = &iwl5000_sensitivity;
-
priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant);
priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant);
priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant;
@@ -836,9 +863,11 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
if (priv->cfg->ops->lib->temp_ops.set_ct_kill)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
+ /* Set initial sensitivity parameters */
/* Set initial calibration set */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_5150:
+ priv->hw_params.sens = &iwl5150_sensitivity;
priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_DC) |
BIT(IWL_CALIB_LO) |
@@ -847,6 +876,7 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
break;
default:
+ priv->hw_params.sens = &iwl5000_sensitivity;
priv->hw_params.calib_init_cfg =
BIT(IWL_CALIB_XTAL) |
BIT(IWL_CALIB_LO) |
@@ -1426,6 +1456,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}
+#define IWL5000_UCODE_GET(item) \
+static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ if (api_ver <= 2) \
+ return le32_to_cpu(ucode->u.v1.item); \
+ return le32_to_cpu(ucode->u.v2.item); \
+}
+
+static u32 iwl5000_ucode_get_header_size(u32 api_ver)
+{
+ if (api_ver <= 2)
+ return UCODE_HEADER_SIZE(1);
+ return UCODE_HEADER_SIZE(2);
+}
+
+static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ if (api_ver <= 2)
+ return 0;
+ return le32_to_cpu(ucode->u.v2.build);
+}
+
+static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ if (api_ver <= 2)
+ return (u8 *) ucode->u.v1.data;
+ return (u8 *) ucode->u.v2.data;
+}
+
+IWL5000_UCODE_GET(inst_size);
+IWL5000_UCODE_GET(data_size);
+IWL5000_UCODE_GET(init_size);
+IWL5000_UCODE_GET(init_data_size);
+IWL5000_UCODE_GET(boot_size);
+
struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
@@ -1441,6 +1509,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.calc_rssi = iwl5000_calc_rssi,
};
+struct iwl_ucode_ops iwl5000_ucode = {
+ .get_header_size = iwl5000_ucode_get_header_size,
+ .get_build = iwl5000_ucode_get_build,
+ .get_inst_size = iwl5000_ucode_get_inst_size,
+ .get_data_size = iwl5000_ucode_get_data_size,
+ .get_init_size = iwl5000_ucode_get_init_size,
+ .get_init_data_size = iwl5000_ucode_get_init_data_size,
+ .get_boot_size = iwl5000_ucode_get_boot_size,
+ .get_data = iwl5000_ucode_get_data,
+};
+
struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -1542,12 +1621,14 @@ static struct iwl_lib_ops iwl5150_lib = {
};
struct iwl_ops iwl5000_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
};
static struct iwl_ops iwl5150_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
@@ -1664,8 +1745,6 @@ MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX));
module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444);
MODULE_PARM_DESC(swcrypto50,
"using software crypto engine (default 0 [hardware])\n");
-module_param_named(debug50, iwl50_mod_params.debug, uint, 0444);
-MODULE_PARM_DESC(debug50, "50XX debug output mask");
module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444);
MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series");
module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444);
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index bd438d8acf5..26c5d4a60d1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -46,8 +46,8 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 2
-#define IWL6050_UCODE_API_MAX 2
+#define IWL6000_UCODE_API_MAX 3
+#define IWL6050_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1
@@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
};
static struct iwl_ops iwl6000_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index ff20e5048a5..63280411fd5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -2466,7 +2466,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct iwl_lq_sta *lq_sta = priv_sta;
int rate_idx;
- u64 mask_bit = 0;
IWL_DEBUG_RATE_LIMIT(priv, "rate scale calculate new rate for skb\n");
@@ -2481,22 +2480,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
lq_sta->max_rate_idx = -1;
}
- if (sta)
- mask_bit = sta->supp_rates[sband->band];
-
/* Send management frames and NO_ACK data using lowest rate. */
- if (!ieee80211_is_data(hdr->frame_control) ||
- info->flags & IEEE80211_TX_CTL_NO_ACK || !sta || !lq_sta) {
- if (!mask_bit)
- info->control.rates[0].idx =
- rate_lowest_index(sband, NULL);
- else
- info->control.rates[0].idx =
- rate_lowest_index(sband, sta);
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- info->control.rates[0].count = 1;
+ if (rate_control_send_low(sta, priv_sta, txrc))
return;
- }
rate_idx = lq_sta->last_txrate_idx;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 355f50ea7fe..44c7f236a7a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -171,7 +171,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
le16_to_cpu(priv->staging_rxon.channel),
priv->staging_rxon.bssid_addr);
- iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
/* Apply the new configuration
* RXON unassoc clears the station table in uCode, send it before
@@ -512,70 +512,6 @@ int iwl_hw_tx_queue_init(struct iwl_priv *priv,
return 0;
}
-
-/******************************************************************************
- *
- * Misc. internal state and helper functions
- *
- ******************************************************************************/
-
-#define MAX_UCODE_BEACON_INTERVAL 4096
-
-static u16 iwl_adjust_beacon_interval(u16 beacon_val)
-{
- u16 new_val = 0;
- u16 beacon_factor = 0;
-
- beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
- new_val = beacon_val / beacon_factor;
-
- if (!new_val)
- new_val = MAX_UCODE_BEACON_INTERVAL;
-
- return new_val;
-}
-
-static void iwl_setup_rxon_timing(struct iwl_priv *priv)
-{
- u64 tsf;
- s32 interval_tm, rem;
- unsigned long flags;
- struct ieee80211_conf *conf = NULL;
- u16 beacon_int = 0;
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
-
- if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- beacon_int = iwl_adjust_beacon_interval(priv->beacon_int);
- priv->rxon_timing.atim_window = 0;
- } else {
- beacon_int = iwl_adjust_beacon_interval(
- priv->vif->bss_conf.beacon_int);
-
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- }
-
- priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
-
- tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
- interval_tm = beacon_int * 1024;
- rem = do_div(tsf, interval_tm);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
-
- spin_unlock_irqrestore(&priv->lock, flags);
- IWL_DEBUG_ASSOC(priv, "beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
/******************************************************************************
*
* Generic RX handler implementations
@@ -597,12 +533,16 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
+ set_bit(STATUS_INIT_UCODE_ALIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
memcpy(&priv->card_alive_init,
&pkt->u.alive_frame,
sizeof(struct iwl_init_alive_resp));
pwork = &priv->init_alive_start;
} else {
IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
+ set_bit(STATUS_RT_UCODE_ALIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
memcpy(&priv->card_alive, &pkt->u.alive_frame,
sizeof(struct iwl_alive_resp));
pwork = &priv->alive_start;
@@ -964,7 +904,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -983,7 +923,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -999,7 +939,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1024,7 +964,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
@@ -1113,7 +1053,7 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1144,7 +1084,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
inta = priv->inta;
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ",
@@ -1156,7 +1096,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -1172,7 +1112,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1197,7 +1137,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
hw_rf_kill = 1;
- IWL_DEBUG_RF_KILL(priv, "RF_KILL bit toggled to %s.\n",
+ IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
hw_rf_kill ? "disable radio" : "enable radio");
priv->isr_stats.rfkill++;
@@ -1348,7 +1288,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
*/
static int iwl_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
const char *name_pre = priv->cfg->fw_name_pre;
@@ -1357,7 +1297,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
char buf[25];
u8 *src;
size_t len;
- u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
+ u32 api_ver, build;
+ u32 inst_size, data_size, init_size, init_data_size, boot_size;
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
@@ -1387,23 +1328,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
if (ret < 0)
goto error;
- /* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ /* Make sure that we got at least the v1 header! */
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+ init_data_size =
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely
@@ -1429,6 +1373,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_UCODE_API(priv->ucode_ver),
IWL_UCODE_SERIAL(priv->ucode_ver));
+ if (build)
+ IWL_DEBUG_INFO(priv, "Build %u\n", build);
+
IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
priv->ucode_ver);
IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
@@ -1443,12 +1390,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
boot_size);
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ if (ucode_raw->size !=
+ priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size +
init_data_size + boot_size) {
- IWL_DEBUG_INFO(priv, "uCode file size %d too small\n",
- (int)ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %d does not match expected size\n",
+ (int)ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -1528,42 +1477,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ len = inst_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len);
+ src += len;
+
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ len = data_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len);
+ src += len;
/* Initialization instructions (3rd block) */
if (init_size) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = init_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
len);
memcpy(priv->ucode_init.v_addr, src, len);
+ src += len;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = init_data_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
len);
memcpy(priv->ucode_init_data.v_addr, src, len);
+ src += len;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ len = boot_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
@@ -1812,6 +1761,11 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter \n");
+ ret = iwl_set_hw_ready(priv);
+ if (priv->hw_ready)
+ return ret;
+
+ /* If HW is not ready, prepare the conditions to check again */
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_PREPARE);
@@ -1819,6 +1773,7 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+ /* HW should be ready by now, check again. */
if (ret != -ETIMEDOUT)
iwl_set_hw_ready(priv);
@@ -1831,6 +1786,7 @@ static int __iwl_up(struct iwl_priv *priv)
{
int i;
int ret;
+ unsigned long status;
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
@@ -1908,6 +1864,51 @@ static int __iwl_up(struct iwl_priv *priv)
/* start card; "initialize" will load runtime ucode */
iwl_nic_start(priv);
+ /* Just finish download Init or Runtime uCode image to device
+ * now we wait here for uCode send REPLY_ALIVE notification
+ * to indicate uCode is ready.
+ * 1) For Init uCode image, all iwlagn devices should wait here
+ * on STATUS_INIT_UCODE_ALIVE status bit; if timeout before
+ * receive the REPLY_ALIVE notification, go back and try to
+ * download the Init uCode image again.
+ * 2) For Runtime uCode image, all iwlagn devices except 4965
+ * wait here on STATUS_RT_UCODE_ALIVE status bit; if
+ * timeout before receive the REPLY_ALIVE notification, go back
+ * and download the Runtime uCode image again.
+ * 3) For 4965 Runtime uCode, it will not go through this path,
+ * need to wait for STATUS_RT_UCODE_ALIVE status bit in
+ * iwl4965_init_alive_start() function; if timeout, need to
+ * restart and download Init uCode image.
+ */
+ if (priv->ucode_type == UCODE_INIT)
+ status = STATUS_INIT_UCODE_ALIVE;
+ else
+ status = STATUS_RT_UCODE_ALIVE;
+ if (test_bit(status, &priv->status)) {
+ IWL_WARN(priv,
+ "%s uCode already alive? "
+ "Waiting for alive anyway\n",
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? "INIT" : "Runtime");
+ clear_bit(status, &priv->status);
+ }
+ ret = wait_event_interruptible_timeout(
+ priv->wait_command_queue,
+ test_bit(status, &priv->status),
+ UCODE_ALIVE_TIMEOUT);
+ if (!ret) {
+ if (!test_bit(status, &priv->status)) {
+ priv->ucode_type =
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? UCODE_NONE : UCODE_INIT;
+ IWL_ERR(priv,
+ "%s timeout after %dms\n",
+ (status == STATUS_INIT_UCODE_ALIVE)
+ ? "INIT" : "Runtime",
+ jiffies_to_msecs(UCODE_ALIVE_TIMEOUT));
+ continue;
+ }
+ }
IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
return 0;
@@ -2331,7 +2332,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
IWL_DEBUG_MAC80211(priv, "enter\n");
- if (priv->hw_params.sw_crypto) {
+ if (priv->cfg->mod_params->sw_crypto) {
IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
return -EOPNOTSUPP;
}
@@ -2455,14 +2456,16 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw,
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
+ *
+ * FIXME This file can be deprecated as the module parameter is
+ * writable and users can thus also change the debug level
+ * using the /sys/module/iwl3945/parameters/debug file.
*/
static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "0x%08X\n", priv->debug_level);
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
}
static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr,
@@ -2476,7 +2479,7 @@ static ssize_t store_debug_level(struct device *d,
if (ret)
IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
else
- priv->debug_level = val;
+ iwl_debug_level = val;
return strnlen(buf, count);
}
@@ -2685,26 +2688,6 @@ static ssize_t show_power_level(struct device *d,
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
store_power_level);
-static ssize_t show_qos(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- char *p = buf;
- int q;
-
- for (q = 0; q < AC_NUM; q++) {
- p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n");
- p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q,
- priv->qos_data.def_qos_parm.ac[q].cw_min,
- priv->qos_data.def_qos_parm.ac[q].cw_max,
- priv->qos_data.def_qos_parm.ac[q].aifsn,
- priv->qos_data.def_qos_parm.ac[q].edca_txop);
- }
-
- return p - buf + 1;
-}
-
-static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL);
static ssize_t show_statistics(struct device *d,
struct device_attribute *attr, char *buf)
@@ -2805,7 +2788,6 @@ static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_debug_level.attr,
#endif
&dev_attr_version.attr,
- &dev_attr_qos.attr,
NULL
};
@@ -2849,7 +2831,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan. */
if (cfg->mod_params->disable_hw_scan) {
- if (cfg->mod_params->debug & IWL_DL_INFO)
+ if (iwl_debug_level & IWL_DL_INFO)
dev_printk(KERN_DEBUG, &(pdev->dev),
"Disabling hw_scan\n");
iwl_hw_ops.hw_scan = NULL;
@@ -2871,7 +2853,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
- priv->debug_level = priv->cfg->mod_params->debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
@@ -3231,3 +3212,11 @@ static void __exit iwl_exit(void)
module_exit(iwl_exit);
module_init(iwl_init);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug50, iwl_debug_level, uint, 0444);
+MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
+module_param_named(debug, iwl_debug_level, uint, 0644);
+MODULE_PARM_DESC(debug, "debug output mask");
+#endif
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index a5d63672ad3..f8bf592e939 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -251,12 +251,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv,
/* increase energy threshold (reduce nrg value)
* to decrease sensitivity */
- if (data->nrg_th_cck >
- (ranges->max_nrg_cck + NRG_STEP_CCK))
- data->nrg_th_cck = data->nrg_th_cck
- - NRG_STEP_CCK;
- else
- data->nrg_th_cck = ranges->max_nrg_cck;
+ data->nrg_th_cck = data->nrg_th_cck - NRG_STEP_CCK;
/* Else if we got fewer than desired, increase sensitivity */
} else if (false_alarms < min_false_alarms) {
data->nrg_curr_state = IWL_FA_TOO_FEW;
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index c87033bf3ad..ebb2fbce536 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -765,6 +765,8 @@ struct iwl5000_rxon_assoc_cmd {
} __attribute__ ((packed));
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
+#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */
+#define IWL39_MAX_UCODE_BEACON_INTERVAL 1 /* 1024 */
/*
* REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
@@ -1922,7 +1924,7 @@ struct iwl_link_qual_general_params {
#define LINK_QUAL_AGG_DISABLE_START_MIN (0)
#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31)
-#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64)
+#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63)
#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0)
/**
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 6ab07165ea2..6aea0264480 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -59,6 +59,9 @@ MODULE_LICENSE("GPL");
IWL_RATE_##pp##M_INDEX, \
IWL_RATE_##np##M_INDEX }
+u32 iwl_debug_level;
+EXPORT_SYMBOL(iwl_debug_level);
+
static irqreturn_t iwl_isr(int irq, void *data);
/*
@@ -635,6 +638,63 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
}
EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
+static u16 iwl_adjust_beacon_interval(u16 beacon_val, u16 max_beacon_val)
+{
+ u16 new_val = 0;
+ u16 beacon_factor = 0;
+
+ beacon_factor = (beacon_val + max_beacon_val) / max_beacon_val;
+ new_val = beacon_val / beacon_factor;
+
+ if (!new_val)
+ new_val = max_beacon_val;
+
+ return new_val;
+}
+
+void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+ u64 tsf;
+ s32 interval_tm, rem;
+ unsigned long flags;
+ struct ieee80211_conf *conf = NULL;
+ u16 beacon_int;
+
+ conf = ieee80211_get_hw_conf(priv->hw);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
+ priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval);
+
+ if (priv->iw_mode == NL80211_IFTYPE_STATION) {
+ beacon_int = priv->beacon_int;
+ priv->rxon_timing.atim_window = 0;
+ } else {
+ beacon_int = priv->vif->bss_conf.beacon_int;
+
+ /* TODO: we need to get atim_window from upper stack
+ * for now we set to 0 */
+ priv->rxon_timing.atim_window = 0;
+ }
+
+ beacon_int = iwl_adjust_beacon_interval(beacon_int,
+ priv->hw_params.max_beacon_itrvl * 1024);
+ priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
+
+ tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
+ interval_tm = beacon_int * 1024;
+ rem = do_div(tsf, interval_tm);
+ priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ IWL_DEBUG_ASSOC(priv,
+ "beacon interval %d beacon timer %d beacon tim %d\n",
+ le16_to_cpu(priv->rxon_timing.beacon_interval),
+ le32_to_cpu(priv->rxon_timing.beacon_init_val),
+ le16_to_cpu(priv->rxon_timing.atim_window));
+}
+EXPORT_SYMBOL(iwl_setup_rxon_timing);
+
void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
{
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
@@ -1218,7 +1278,7 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
IWL_DEBUG_RADIO(priv, "RX CONFIG:\n");
- iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+ iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
IWL_DEBUG_RADIO(priv, "u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
IWL_DEBUG_RADIO(priv, "u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
IWL_DEBUG_RADIO(priv, "u32 filter_flags: 0x%08x\n",
@@ -1233,6 +1293,209 @@ static void iwl_print_rx_config_cmd(struct iwl_priv *priv)
}
#endif
+static const char *desc_lookup_text[] = {
+ "OK",
+ "FAIL",
+ "BAD_PARAM",
+ "BAD_CHECKSUM",
+ "NMI_INTERRUPT_WDG",
+ "SYSASSERT",
+ "FATAL_ERROR",
+ "BAD_COMMAND",
+ "HW_ERROR_TUNE_LOCK",
+ "HW_ERROR_TEMPERATURE",
+ "ILLEGAL_CHAN_FREQ",
+ "VCC_NOT_STABLE",
+ "FH_ERROR",
+ "NMI_INTERRUPT_HOST",
+ "NMI_INTERRUPT_ACTION_PT",
+ "NMI_INTERRUPT_UNKNOWN",
+ "UCODE_VERSION_MISMATCH",
+ "HW_ERROR_ABS_LOCK",
+ "HW_ERROR_CAL_LOCK_FAIL",
+ "NMI_INTERRUPT_INST_ACTION_PT",
+ "NMI_INTERRUPT_DATA_ACTION_PT",
+ "NMI_TRM_HW_ER",
+ "NMI_INTERRUPT_TRM",
+ "NMI_INTERRUPT_BREAK_POINT"
+ "DEBUG_0",
+ "DEBUG_1",
+ "DEBUG_2",
+ "DEBUG_3",
+ "UNKNOWN"
+};
+
+static const char *desc_lookup(int i)
+{
+ int max = ARRAY_SIZE(desc_lookup_text) - 1;
+
+ if (i < 0 || i > max)
+ i = max;
+
+ return desc_lookup_text[i];
+}
+
+#define ERROR_START_OFFSET (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+ u32 data2, line;
+ u32 desc, time, count, base, data1;
+ u32 blink1, blink2, ilink1, ilink2;
+
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
+ return;
+ }
+
+ count = iwl_read_targ_mem(priv, base);
+
+ if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ IWL_ERR(priv, "Start IWL Error Log Dump:\n");
+ IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
+ priv->status, count);
+ }
+
+ desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+ blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
+ blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
+ ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
+ ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+ data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+ data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
+ line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
+ time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
+
+ IWL_ERR(priv, "Desc Time "
+ "data1 data2 line\n");
+ IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
+ desc_lookup(desc), desc, time, data1, data2, line);
+ IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n");
+ IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+ ilink1, ilink2);
+
+}
+
+#define EVENT_START_OFFSET (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+ u32 num_events, u32 mode)
+{
+ u32 i;
+ u32 base; /* SRAM byte address of event log header */
+ u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
+ u32 ptr; /* SRAM byte address of log data */
+ u32 ev, time, data; /* event log data */
+
+ if (num_events == 0)
+ return;
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (mode == 0)
+ event_size = 2 * sizeof(u32);
+ else
+ event_size = 3 * sizeof(u32);
+
+ ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+ /* "time" is actually "data" for mode 0 (no timestamp).
+ * place event id # at far right for easier visual parsing. */
+ for (i = 0; i < num_events; i++) {
+ ev = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ time = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ if (mode == 0) {
+ /* data, ev */
+ IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
+ } else {
+ data = iwl_read_targ_mem(priv, ptr);
+ ptr += sizeof(u32);
+ IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
+ time, data, ev);
+ }
+ }
+}
+
+void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+ u32 base; /* SRAM byte address of event log header */
+ u32 capacity; /* event log capacity in # entries */
+ u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
+ u32 num_wraps; /* # times uCode wrapped to top of log */
+ u32 next_entry; /* index of next entry to be written by uCode */
+ u32 size; /* # entries that we'll print */
+
+ switch (priv->ucode_type) {
+ case UCODE_RT:
+ base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ break;
+ case UCODE_INIT:
+ base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ break;
+ default:
+ IWL_ERR(priv, "uCode image not available\n");
+ return;
+ }
+
+ if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
+ IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
+ return;
+ }
+
+ /* event log header */
+ capacity = iwl_read_targ_mem(priv, base);
+ mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+ num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+ next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
+
+ size = num_wraps ? capacity : next_entry;
+
+ /* bail out if nothing in log */
+ if (size == 0) {
+ IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
+ return;
+ }
+
+ IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
+ size, num_wraps);
+
+ /* if uCode has wrapped back to top of log, start at the oldest entry,
+ * i.e the next one that uCode would fill. */
+ if (num_wraps)
+ iwl_print_event_log(priv, next_entry,
+ capacity - next_entry, mode);
+ /* (then/else) start at top of log */
+ iwl_print_event_log(priv, 0, next_entry, mode);
+
+}
/**
* iwl_irq_handle_error - called for HW or SW error interrupt from card
*/
@@ -1245,7 +1508,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_FW_ERRORS) {
+ if (iwl_debug_level & IWL_DL_FW_ERRORS) {
iwl_dump_nic_error_log(priv);
iwl_dump_nic_event_log(priv);
iwl_print_rx_config_cmd(priv);
@@ -1325,7 +1588,8 @@ int iwl_setup_mac(struct iwl_priv *priv)
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_NOISE_DBM |
IEEE80211_HW_AMPDU_AGGREGATION |
- IEEE80211_HW_SPECTRUM_MGMT;
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_SUPPORTS_PS;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
@@ -1361,7 +1625,6 @@ EXPORT_SYMBOL(iwl_setup_mac);
int iwl_set_hw_params(struct iwl_priv *priv)
{
- priv->hw_params.sw_crypto = priv->cfg->mod_params->sw_crypto;
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
if (priv->cfg->mod_params->amsdu_size_8K)
@@ -1370,6 +1633,8 @@ int iwl_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_buf_size = IWL_RX_BUF_SIZE_4K;
priv->hw_params.max_pkt_size = priv->hw_params.rx_buf_size - 256;
+ priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
+
if (priv->cfg->mod_params->disable_11n)
priv->cfg->sku &= ~IWL_SKU_N;
@@ -1484,31 +1749,6 @@ void iwl_uninit_drv(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_uninit_drv);
-
-void iwl_disable_interrupts(struct iwl_priv *priv)
-{
- clear_bit(STATUS_INT_ENABLED, &priv->status);
-
- /* disable interrupts from uCode/NIC to host */
- iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
- /* acknowledge/clear/reset any interrupts still pending
- * from uCode or flow handler (Rx/Tx DMA) */
- iwl_write32(priv, CSR_INT, 0xffffffff);
- iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
- IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
-}
-EXPORT_SYMBOL(iwl_disable_interrupts);
-
-void iwl_enable_interrupts(struct iwl_priv *priv)
-{
- IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
- set_bit(STATUS_INT_ENABLED, &priv->status);
- iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
-}
-EXPORT_SYMBOL(iwl_enable_interrupts);
-
-
#define ICT_COUNT (PAGE_SIZE/sizeof(u32))
/* Free dram table */
@@ -1742,7 +1982,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, "
"fh 0x%08x\n", inta, inta_mask, inta_fh);
@@ -1981,191 +2221,6 @@ int iwl_verify_ucode(struct iwl_priv *priv)
EXPORT_SYMBOL(iwl_verify_ucode);
-static const char *desc_lookup_text[] = {
- "OK",
- "FAIL",
- "BAD_PARAM",
- "BAD_CHECKSUM",
- "NMI_INTERRUPT_WDG",
- "SYSASSERT",
- "FATAL_ERROR",
- "BAD_COMMAND",
- "HW_ERROR_TUNE_LOCK",
- "HW_ERROR_TEMPERATURE",
- "ILLEGAL_CHAN_FREQ",
- "VCC_NOT_STABLE",
- "FH_ERROR",
- "NMI_INTERRUPT_HOST",
- "NMI_INTERRUPT_ACTION_PT",
- "NMI_INTERRUPT_UNKNOWN",
- "UCODE_VERSION_MISMATCH",
- "HW_ERROR_ABS_LOCK",
- "HW_ERROR_CAL_LOCK_FAIL",
- "NMI_INTERRUPT_INST_ACTION_PT",
- "NMI_INTERRUPT_DATA_ACTION_PT",
- "NMI_TRM_HW_ER",
- "NMI_INTERRUPT_TRM",
- "NMI_INTERRUPT_BREAK_POINT"
- "DEBUG_0",
- "DEBUG_1",
- "DEBUG_2",
- "DEBUG_3",
- "UNKNOWN"
-};
-
-static const char *desc_lookup(int i)
-{
- int max = ARRAY_SIZE(desc_lookup_text) - 1;
-
- if (i < 0 || i > max)
- i = max;
-
- return desc_lookup_text[i];
-}
-
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-
-void iwl_dump_nic_error_log(struct iwl_priv *priv)
-{
- u32 data2, line;
- u32 desc, time, count, base, data1;
- u32 blink1, blink2, ilink1, ilink2;
-
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERR(priv, "Not valid error log pointer 0x%08X\n", base);
- return;
- }
-
- count = iwl_read_targ_mem(priv, base);
-
- if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
- IWL_ERR(priv, "Start IWL Error Log Dump:\n");
- IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
- priv->status, count);
- }
-
- desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
- blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
- blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
- ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
- ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
- data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
- data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
- line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
- time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
-
- IWL_ERR(priv, "Desc Time "
- "data1 data2 line\n");
- IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",
- desc_lookup(desc), desc, time, data1, data2, line);
- IWL_ERR(priv, "blink1 blink2 ilink1 ilink2\n");
- IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
- ilink1, ilink2);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_error_log);
-
-#define EVENT_START_OFFSET (4 * sizeof(u32))
-
-/**
- * iwl_print_event_log - Dump error event log to syslog
- *
- */
-static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
- u32 num_events, u32 mode)
-{
- u32 i;
- u32 base; /* SRAM byte address of event log header */
- u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */
- u32 ptr; /* SRAM byte address of log data */
- u32 ev, time, data; /* event log data */
-
- if (num_events == 0)
- return;
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (mode == 0)
- event_size = 2 * sizeof(u32);
- else
- event_size = 3 * sizeof(u32);
-
- ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
-
- /* "time" is actually "data" for mode 0 (no timestamp).
- * place event id # at far right for easier visual parsing. */
- for (i = 0; i < num_events; i++) {
- ev = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- time = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- if (mode == 0) {
- /* data, ev */
- IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", time, ev);
- } else {
- data = iwl_read_targ_mem(priv, ptr);
- ptr += sizeof(u32);
- IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n",
- time, data, ev);
- }
- }
-}
-
-void iwl_dump_nic_event_log(struct iwl_priv *priv)
-{
- u32 base; /* SRAM byte address of event log header */
- u32 capacity; /* event log capacity in # entries */
- u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */
- u32 num_wraps; /* # times uCode wrapped to top of log */
- u32 next_entry; /* index of next entry to be written by uCode */
- u32 size; /* # entries that we'll print */
-
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
-
- if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
- IWL_ERR(priv, "Invalid event log pointer 0x%08X\n", base);
- return;
- }
-
- /* event log header */
- capacity = iwl_read_targ_mem(priv, base);
- mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
- num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
- next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
-
- size = num_wraps ? capacity : next_entry;
-
- /* bail out if nothing in log */
- if (size == 0) {
- IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n");
- return;
- }
-
- IWL_ERR(priv, "Start IWL Event Log Dump: display count %d, wraps %d\n",
- size, num_wraps);
-
- /* if uCode has wrapped back to top of log, start at the oldest entry,
- * i.e the next one that uCode would fill. */
- if (num_wraps)
- iwl_print_event_log(priv, next_entry,
- capacity - next_entry, mode);
- /* (then/else) start at top of log */
- iwl_print_event_log(priv, 0, next_entry, mode);
-
-}
-EXPORT_SYMBOL(iwl_dump_nic_event_log);
-
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{
struct iwl_ct_kill_config cmd;
@@ -2234,7 +2289,7 @@ void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
"notification for %s:\n",
le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
- iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+ iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
}
EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index dabf663e36e..614ec7cc5b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -116,6 +116,17 @@ struct iwl_temp_ops {
void (*set_ct_kill)(struct iwl_priv *priv);
};
+struct iwl_ucode_ops {
+ u32 (*get_header_size)(u32);
+ u32 (*get_build)(const struct iwl_ucode_header *, u32);
+ u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
+ u8 * (*get_data)(const struct iwl_ucode_header *, u32);
+};
+
struct iwl_lib_ops {
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
@@ -171,6 +182,7 @@ struct iwl_lib_ops {
};
struct iwl_ops {
+ const struct iwl_ucode_ops *ucode;
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
@@ -178,7 +190,6 @@ struct iwl_ops {
struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */
- u32 debug; /* def: 0 = minimal debug log messages */
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
int num_of_ampdu_queues;/* def: HW dependent */
@@ -384,7 +395,6 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
void iwl_init_scan_params(struct iwl_priv *priv);
int iwl_scan_cancel(struct iwl_priv *priv);
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
-int iwl_scan_initiate(struct iwl_priv *priv);
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
const u8 *ie, int ie_len, int left);
@@ -398,7 +408,6 @@ void iwl_bg_scan_check(struct work_struct *data);
void iwl_bg_abort_scan(struct work_struct *work);
void iwl_bg_scan_completed(struct work_struct *work);
void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
-int iwl_send_scan_abort(struct iwl_priv *priv);
/* For faster active scanning, scan will move to the next channel if fewer than
* PLCP_QUIET_THRESH packets are heard on this channel within
@@ -449,8 +458,6 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
/*****************************************************
* PCI *
*****************************************************/
-void iwl_disable_interrupts(struct iwl_priv *priv);
-void iwl_enable_interrupts(struct iwl_priv *priv);
irqreturn_t iwl_isr_legacy(int irq, void *data);
int iwl_reset_ict(struct iwl_priv *priv);
void iwl_disable_ict(struct iwl_priv *priv);
@@ -474,7 +481,6 @@ int iwl_pci_resume(struct pci_dev *pdev);
/*****************************************************
* Error Handling Debugging
******************************************************/
-void iwl_dump_nic_error_log(struct iwl_priv *priv);
void iwl_dump_nic_event_log(struct iwl_priv *priv);
void iwl_clear_isr_stats(struct iwl_priv *priv);
@@ -503,6 +509,8 @@ void iwlcore_free_geos(struct iwl_priv *priv);
#define STATUS_POWER_PMI 16
#define STATUS_FW_ERROR 17
#define STATUS_MODE_PENDING 18
+#define STATUS_INIT_UCODE_ALIVE 19
+#define STATUS_RT_UCODE_ALIVE 20
static inline int iwl_is_ready(struct iwl_priv *priv)
@@ -556,6 +564,7 @@ extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_setup_rxon_timing(struct iwl_priv *priv);
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
{
return priv->cfg->ops->hcmd->rxon_assoc(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index 2cf014f523b..9faf0c2ff60 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -30,16 +30,23 @@
#define __iwl_debug_h__
struct iwl_priv;
+extern u32 iwl_debug_level;
#define IWL_ERR(p, f, a...) dev_err(&((p)->pci_dev->dev), f, ## a)
#define IWL_WARN(p, f, a...) dev_warn(&((p)->pci_dev->dev), f, ## a)
#define IWL_INFO(p, f, a...) dev_info(&((p)->pci_dev->dev), f, ## a)
#define IWL_CRIT(p, f, a...) dev_crit(&((p)->pci_dev->dev), f, ## a)
+#define iwl_print_hex_error(priv, p, len) \
+do { \
+ print_hex_dump(KERN_ERR, "iwl data: ", \
+ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
+} while (0)
+
#ifdef CONFIG_IWLWIFI_DEBUG
#define IWL_DEBUG(__priv, level, fmt, args...) \
do { \
- if (__priv->debug_level & (level)) \
+ if (iwl_debug_level & (level)) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
@@ -47,15 +54,15 @@ do { \
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \
do { \
- if ((__priv->debug_level & (level)) && net_ratelimit()) \
+ if ((iwl_debug_level & (level)) && net_ratelimit()) \
dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \
"%c %s " fmt, in_interrupt() ? 'I' : 'U', \
__func__ , ## args); \
} while (0)
-#define iwl_print_hex_dump(priv, level, p, len) \
+#define iwl_print_hex_dump(level, p, len) \
do { \
- if (priv->debug_level & level) \
+ if (iwl_debug_level & level) \
print_hex_dump(KERN_DEBUG, "iwl data: ", \
DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \
} while (0)
@@ -76,6 +83,10 @@ struct iwl_debugfs {
struct dentry *file_channels;
struct dentry *file_status;
struct dentry *file_interrupt;
+ struct dentry *file_qos;
+#ifdef CONFIG_IWLWIFI_LEDS
+ struct dentry *file_led;
+#endif
} dbgfs_data_files;
struct dir_rf_files {
struct dentry *file_disable_sensitivity;
@@ -93,8 +104,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv);
#else
#define IWL_DEBUG(__priv, level, fmt, args...)
#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...)
-static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level,
- void *p, u32 len)
+static inline void iwl_print_hex_dump(int level, void *p, u32 len)
{}
#endif /* CONFIG_IWLWIFI_DEBUG */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 11e08c06891..0ab3463aa07 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -49,7 +49,8 @@
#define DEBUGFS_ADD_FILE(name, parent) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
+ debugfs_create_file(#name, S_IWUSR | S_IRUSR, \
+ dbgfs->dir_##parent, priv, \
&iwl_dbgfs_##name##_ops); \
if (!(dbgfs->dbgfs_##parent##_files.file_##name)) \
goto err; \
@@ -57,7 +58,8 @@
#define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \
+ debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \
+ dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
@@ -65,7 +67,7 @@
#define DEBUGFS_ADD_X32(name, parent, ptr) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
- debugfs_create_x32(#name, 0444, dbgfs->dir_##parent, ptr); \
+ debugfs_create_x32(#name, S_IRUSR, dbgfs->dir_##parent, ptr); \
if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \
|| !dbgfs->dbgfs_##parent##_files.file_##name) \
goto err; \
@@ -566,6 +568,55 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
return count;
}
+static ssize_t iwl_dbgfs_qos_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0, i;
+ char buf[256];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ for (i = 0; i < AC_NUM; i++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\tcw_min\tcw_max\taifsn\ttxop\n");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "AC[%d]\t%u\t%u\t%u\t%u\n", i,
+ priv->qos_data.def_qos_parm.ac[i].cw_min,
+ priv->qos_data.def_qos_parm.ac[i].cw_max,
+ priv->qos_data.def_qos_parm.ac[i].aifsn,
+ priv->qos_data.def_qos_parm.ac[i].edca_txop);
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+
+#ifdef CONFIG_IWLWIFI_LEDS
+static ssize_t iwl_dbgfs_led_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)file->private_data;
+ int pos = 0;
+ char buf[256];
+ const size_t bufsz = sizeof(buf);
+ ssize_t ret;
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "allow blinking: %s\n",
+ (priv->allow_blinking) ? "True" : "False");
+ if (priv->allow_blinking) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Led blinking rate: %u\n",
+ priv->last_blink_rate);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "Last blink time: %lu\n",
+ priv->last_blink_time);
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ return ret;
+}
+#endif
DEBUGFS_READ_WRITE_FILE_OPS(sram);
DEBUGFS_WRITE_FILE_OPS(log_event);
@@ -576,6 +627,10 @@ DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_FILE_OPS(channels);
DEBUGFS_READ_FILE_OPS(status);
DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_FILE_OPS(qos);
+#ifdef CONFIG_IWLWIFI_LEDS
+DEBUGFS_READ_FILE_OPS(led);
+#endif
/*
* Create the debugfs files and directories
@@ -612,10 +667,17 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(channels, data);
DEBUGFS_ADD_FILE(status, data);
DEBUGFS_ADD_FILE(interrupt, data);
+ DEBUGFS_ADD_FILE(qos, data);
+#ifdef CONFIG_IWLWIFI_LEDS
+ DEBUGFS_ADD_FILE(led, data);
+#endif
DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal);
DEBUGFS_ADD_BOOL(disable_chain_noise, rf,
&priv->disable_chain_noise_cal);
- DEBUGFS_ADD_BOOL(disable_tx_power, rf, &priv->disable_tx_power_cal);
+ if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
+ ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+ DEBUGFS_ADD_BOOL(disable_tx_power, rf,
+ &priv->disable_tx_power_cal);
return 0;
err:
@@ -643,10 +705,16 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_status);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_interrupt);
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_qos);
+#ifdef CONFIG_IWLWIFI_LEDS
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_led);
+#endif
DEBUGFS_REMOVE(priv->dbgfs->dir_data);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity);
DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise);
- DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
+ if (((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) ||
+ ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_3945))
+ DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_tx_power);
DEBUGFS_REMOVE(priv->dbgfs->dir_rf);
DEBUGFS_REMOVE(priv->dbgfs->dir_drv);
kfree(priv->dbgfs);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 650e20af20f..0751891f4ab 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg;
/* shared structures from iwl-5000.c */
extern struct iwl_mod_params iwl50_mod_params;
extern struct iwl_ops iwl5000_ops;
+extern struct iwl_ucode_ops iwl5000_ucode;
extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_hcmd_ops iwl5000_hcmd;
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
@@ -525,15 +526,29 @@ struct fw_desc {
};
/* uCode file layout */
-struct iwl_ucode {
- __le32 ver; /* major/minor/API/serial */
- __le32 inst_size; /* bytes of runtime instructions */
- __le32 data_size; /* bytes of runtime data */
- __le32 init_size; /* bytes of initialization instructions */
- __le32 init_data_size; /* bytes of initialization data */
- __le32 boot_size; /* bytes of bootstrap instructions */
- u8 data[0]; /* data in same order as "size" elements */
+struct iwl_ucode_header {
+ __le32 ver; /* major/minor/API/serial */
+ union {
+ struct {
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v1;
+ struct {
+ __le32 build; /* build number */
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v2;
+ } u;
};
+#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
struct iwl4965_ibss_seq {
u8 mac[ETH_ALEN];
@@ -610,7 +625,7 @@ struct iwl_hw_params {
u8 max_stations;
u8 bcast_sta_id;
u8 fat_channel;
- u8 sw_crypto;
+ u8 max_beacon_itrvl; /* in 1024 ms */
u32 max_inst_size;
u32 max_data_size;
u32 max_bsm_size;
@@ -757,6 +772,8 @@ struct iwl_calib_result {
size_t buf_len;
};
+#define UCODE_ALIVE_TIMEOUT (5 * HZ)
+
enum ucode_type {
UCODE_NONE = 0,
UCODE_INIT,
@@ -1094,7 +1111,6 @@ struct iwl_priv {
#ifdef CONFIG_IWLWIFI_DEBUG
/* debugging info */
- u32 debug_level;
u32 framecnt_to_us;
atomic_t restrict_refcnt;
#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 7d7554a2f34..51eed722666 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -159,6 +159,9 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
/* OTP only valid for CP/PP and after */
switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ case CSR_HW_REV_TYPE_NONE:
+ IWL_ERR(priv, "Unknown hardware type\n");
+ return -ENOENT;
case CSR_HW_REV_TYPE_3945:
case CSR_HW_REV_TYPE_4965:
case CSR_HW_REV_TYPE_5300:
@@ -266,7 +269,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
u32 otpgp;
priv->nvm_device_type = iwlcore_get_nvm_type(priv);
-
+ if (priv->nvm_device_type == -ENOENT)
+ return -ENOENT;
/* allocate eeprom */
if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
priv->cfg->eeprom_size =
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index a1328c3c81a..bd0b12efb5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -145,4 +145,25 @@ static inline void iwl_stop_queue(struct iwl_priv *priv, u8 queue)
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+ clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+ /* disable interrupts from uCode/NIC to host */
+ iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+ /* acknowledge/clear/reset any interrupts still pending
+ * from uCode or flow handler (Rx/Tx DMA) */
+ iwl_write32(priv, CSR_INT, 0xffffffff);
+ iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+ IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
+}
+
+static inline void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
+ set_bit(STATUS_INT_ENABLED, &priv->status);
+ iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
+}
+
#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index 5e64252f80f..8c8115293b3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -54,7 +54,7 @@ static const char *led_type_str[] = {
static const struct {
- u16 tpt;
+ u16 tpt; /* Mb/s */
u8 on_time;
u8 off_time;
} blink_tbl[] =
@@ -104,7 +104,7 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
}
/* Set led pattern command */
-static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
+static int iwl_led_pattern(struct iwl_priv *priv, int led_id,
unsigned int idx)
{
struct iwl_led_cmd led_cmd = {
@@ -121,7 +121,7 @@ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
}
/* Set led register off */
-static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
+static int iwl_led_on_reg(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "led on %d\n", led_id);
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
@@ -130,7 +130,7 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
#if 0
/* Set led on command */
-static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
+static int iwl_led_on(struct iwl_priv *priv, int led_id)
{
struct iwl_led_cmd led_cmd = {
.id = led_id,
@@ -142,7 +142,7 @@ static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
}
/* Set led off command */
-int iwl4965_led_off(struct iwl_priv *priv, int led_id)
+int iwl_led_off(struct iwl_priv *priv, int led_id)
{
struct iwl_led_cmd led_cmd = {
.id = led_id,
@@ -157,7 +157,7 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id)
/* Set led register off */
-static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
+static int iwl_led_off_reg(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "LED Reg off\n");
iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
@@ -171,7 +171,7 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id)
{
IWL_DEBUG_LED(priv, "Associated\n");
priv->allow_blinking = 1;
- return iwl4965_led_on_reg(priv, led_id);
+ return iwl_led_on_reg(priv, led_id);
}
static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
{
@@ -264,13 +264,15 @@ static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led,
/*
- * calculate blink rate according to last 2 sec Tx/Rx activities
+ * calculate blink rate according to last second Tx/Rx activities
*/
static int iwl_get_blink_rate(struct iwl_priv *priv)
{
int i;
- u64 current_tpt = priv->tx_stats[2].bytes;
- /* FIXME: + priv->rx_stats[2].bytes; */
+ /* count both tx and rx traffic to be able to
+ * handle traffic in either direction
+ */
+ u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
s64 tpt = current_tpt - priv->led_tpt;
if (tpt < 0) /* wraparound */
@@ -314,7 +316,7 @@ void iwl_leds_background(struct iwl_priv *priv)
priv->last_blink_time = 0;
if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) {
priv->last_blink_rate = IWL_SOLID_BLINK_IDX;
- iwl4965_led_pattern(priv, IWL_LED_LINK,
+ iwl_led_pattern(priv, IWL_LED_LINK,
IWL_SOLID_BLINK_IDX);
}
return;
@@ -328,7 +330,7 @@ void iwl_leds_background(struct iwl_priv *priv)
/* call only if blink rate change */
if (blink_idx != priv->last_blink_rate)
- iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx);
+ iwl_led_pattern(priv, IWL_LED_LINK, blink_idx);
priv->last_blink_time = jiffies;
priv->last_blink_rate = blink_idx;
@@ -351,8 +353,8 @@ int iwl_leds_register(struct iwl_priv *priv)
sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
wiphy_name(priv->hw->wiphy));
- priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg;
- priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
+ priv->led[IWL_LED_TRG_RADIO].led_on = iwl_led_on_reg;
+ priv->led[IWL_LED_TRG_RADIO].led_off = iwl_led_off_reg;
priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO],
@@ -386,7 +388,7 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
+ priv->led[IWL_LED_TRG_RX].led_pattern = iwl_led_pattern;
if (ret)
goto exit_fail;
@@ -401,7 +403,7 @@ int iwl_leds_register(struct iwl_priv *priv)
priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated;
priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated;
- priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
+ priv->led[IWL_LED_TRG_TX].led_pattern = iwl_led_pattern;
if (ret)
goto exit_fail;
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 3b9cac3fd21..d393e8f0210 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -80,6 +80,8 @@
#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
+#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
+#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
@@ -91,7 +93,8 @@
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
-
+#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
+#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 2b8d40b37a1..5d5f2153f44 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -646,7 +646,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
u32 tsf_low;
int rssi;
- if (likely(!(priv->debug_level & IWL_DL_RX)))
+ if (likely(!(iwl_debug_level & IWL_DL_RX)))
return;
/* MAC header */
@@ -742,7 +742,7 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv,
}
}
if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
+ iwl_print_hex_dump(IWL_DL_RX, header, length);
}
#endif
@@ -927,12 +927,13 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
hdr = (struct ieee80211_hdr *)rxb->skb->data;
/* in case of HW accelerated crypto and bad decryption, drop */
- if (!priv->hw_params.sw_crypto &&
+ if (!priv->cfg->mod_params->sw_crypto &&
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len);
- ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+ memcpy(IEEE80211_SKB_RXCB(rxb->skb), stats, sizeof(*stats));
+ ieee80211_rx_irqsafe(priv->hw, rxb->skb);
priv->alloc_rxb_skb--;
rxb->skb = NULL;
}
@@ -1060,11 +1061,11 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
/* Set "1" to report good data frames in groups of 100 */
#ifdef CONFIG_IWLWIFI_DEBUG
- if (unlikely(priv->debug_level & IWL_DL_RX))
+ if (unlikely(iwl_debug_level & IWL_DL_RX))
iwl_dbg_report_frame(priv, rx_start, len, header, 1);
#endif
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n",
- rx_status.signal, rx_status.noise, rx_status.signal,
+ rx_status.signal, rx_status.noise, rx_status.qual,
(unsigned long long)rx_status.mactime);
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index e26875dbe85..00398d973a0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -109,7 +109,7 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
}
EXPORT_SYMBOL(iwl_scan_cancel_timeout);
-int iwl_send_scan_abort(struct iwl_priv *priv)
+static int iwl_send_scan_abort(struct iwl_priv *priv)
{
int ret = 0;
struct iwl_rx_packet *res;
@@ -150,7 +150,6 @@ int iwl_send_scan_abort(struct iwl_priv *priv)
return ret;
}
-EXPORT_SYMBOL(iwl_send_scan_abort);
/* Service response to REPLY_SCAN_CMD (0x80) */
static void iwl_rx_reply_scan(struct iwl_priv *priv,
@@ -322,7 +321,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
u8 is_active, u8 n_probes,
struct iwl_scan_channel *scan_ch)
{
- const struct ieee80211_channel *channels = NULL;
+ struct ieee80211_channel *chan;
const struct ieee80211_supported_band *sband;
const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
@@ -334,20 +333,19 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
if (!sband)
return 0;
- channels = sband->channels;
-
active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
passive_dwell = iwl_get_passive_dwell_time(priv, band);
if (passive_dwell <= active_dwell)
passive_dwell = active_dwell + 1;
- for (i = 0, added = 0; i < sband->n_channels; i++) {
- if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+ for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+
+ if (chan->band != band)
continue;
- channel =
- ieee80211_frequency_to_channel(channels[i].center_freq);
+ channel = ieee80211_frequency_to_channel(chan->center_freq);
scan_ch->channel = cpu_to_le16(channel);
ch_info = iwl_get_channel_info(priv, band, channel);
@@ -358,7 +356,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
}
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
else
scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
@@ -405,7 +403,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
}
-int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl_scan_initiate(struct iwl_priv *priv)
{
if (!iwl_is_ready_rf(priv)) {
IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n");
@@ -423,10 +421,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
}
IWL_DEBUG_INFO(priv, "Starting scan...\n");
- if (priv->cfg->sku & IWL_SKU_G)
- priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
- if (priv->cfg->sku & IWL_SKU_A)
- priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
set_bit(STATUS_SCANNING, &priv->status);
priv->scan_start = jiffies;
priv->scan_pass_start = priv->scan_start;
@@ -435,7 +429,6 @@ int iwl_scan_initiate(struct iwl_priv *priv)
return 0;
}
-EXPORT_SYMBOL(iwl_scan_initiate);
#define IWL_DELAY_NEXT_SCAN (HZ*2)
@@ -444,7 +437,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
{
unsigned long flags;
struct iwl_priv *priv = hw->priv;
- int ret;
+ int ret, i;
IWL_DEBUG_MAC80211(priv, "enter\n");
@@ -478,6 +471,10 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
+ priv->scan_bands = 0;
+ for (i = 0; i < req->n_channels; i++)
+ priv->scan_bands |= BIT(req->channels[i]->band);
+
priv->scan_request = req;
ret = iwl_scan_initiate(priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 2addf735b19..cbe4e26d053 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -566,6 +566,8 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
unsigned long flags;
spin_lock_irqsave(&priv->sta_lock, flags);
+ IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n",
+ keyconf->keyidx);
if (!test_and_clear_bit(keyconf->keyidx, &priv->ucode_key_table))
IWL_ERR(priv, "index %d not used in uCode key table.\n",
@@ -573,6 +575,11 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv,
priv->default_wep_key--;
memset(&priv->wep_keys[keyconf->keyidx], 0, sizeof(priv->wep_keys[0]));
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n");
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
ret = iwl_send_static_wepkey_cmd(priv, 1);
IWL_DEBUG_WEP(priv, "Remove default WEP key: idx=%d ret=%d\n",
keyconf->keyidx, ret);
@@ -853,6 +860,11 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ if (iwl_is_rfkill(priv)) {
+ IWL_DEBUG_WEP(priv, "Not sending REPLY_ADD_STA command because RFKILL enabled. \n");
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+ return 0;
+ }
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
@@ -1044,11 +1056,10 @@ EXPORT_SYMBOL(iwl_rxon_add_station);
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
{
int sta_id;
- u16 fc = le16_to_cpu(hdr->frame_control);
+ __le16 fc = hdr->frame_control;
/* If this frame is broadcast or management, use broadcast station id */
- if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
- is_multicast_ether_addr(hdr->addr1))
+ if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
return priv->hw_params.bcast_sta_id;
switch (priv->iw_mode) {
@@ -1082,7 +1093,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
IWL_DEBUG_DROP(priv, "Station %pM not in station map. "
"Defaulting to broadcast...\n",
hdr->addr1);
- iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+ iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
return priv->hw_params.bcast_sta_id;
default:
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 2e89040e63b..c7100b9dced 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -348,6 +348,10 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
txq->need_update = 0;
+ /* aggregation TX queues will get their ID when aggregation begins */
+ if (txq_id <= IWL_TX_FIFO_AC3)
+ txq->swq_id = txq_id;
+
/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
* iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
@@ -732,8 +736,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
- swq_id = skb_get_queue_mapping(skb);
- txq_id = swq_id;
+ txq_id = skb_get_queue_mapping(skb);
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
@@ -744,15 +747,13 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr->seq_ctrl |= cpu_to_le16(seq_number);
seq_number += 0x10;
/* aggregation is on for this <sta,tid> */
- if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
- swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
- }
}
txq = &priv->txq[txq_id];
+ swq_id = txq->swq_id;
q = &txq->q;
- txq->swq_id = swq_id;
if (unlikely(iwl_queue_space(q) < q->high_mark))
goto drop_unlock;
@@ -869,8 +870,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
le16_to_cpu(out_cmd->hdr.sequence));
IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx_cmd->tx_flags));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
/* Set up entry for this TFD in Tx byte-count array */
if (info->flags & IEEE80211_TX_CTL_AMPDU)
@@ -939,7 +940,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
!(cmd->meta.flags & CMD_SIZE_HUGE));
if (iwl_is_rfkill(priv)) {
- IWL_DEBUG_INFO(priv, "Not sending command - RF KILL");
+ IWL_DEBUG_INFO(priv, "Not sending command - RF KILL\n");
return -EIO;
}
@@ -1109,7 +1110,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
txq_id, sequence,
priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
- iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32);
+ iwl_print_hex_error(priv, rxb, 32);
return;
}
@@ -1189,6 +1190,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
tid_data = &priv->stations[sta_id].tid[tid];
*ssn = SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
+ priv->txq[txq_id].swq_id = iwl_virtual_agg_queue_num(tx_fifo, txq_id);
spin_unlock_irqrestore(&priv->sta_lock, flags);
ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 2f50ab60bfd..2cc7e30d774 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL");
/* module parameters */
struct iwl_mod_params iwl3945_mod_params = {
- .num_of_queues = IWL39_MAX_NUM_QUEUES,
+ .num_of_queues = IWL39_NUM_QUEUES, /* Not used */
.sw_crypto = 1,
.restart_fw = 1,
/* the rest are 0 by default */
@@ -361,76 +361,6 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv)
priv->shared_phys);
}
-#define MAX_UCODE_BEACON_INTERVAL 1024
-#define INTEL_CONN_LISTEN_INTERVAL cpu_to_le16(0xA)
-
-static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val)
-{
- u16 new_val = 0;
- u16 beacon_factor = 0;
-
- beacon_factor =
- (beacon_val + MAX_UCODE_BEACON_INTERVAL)
- / MAX_UCODE_BEACON_INTERVAL;
- new_val = beacon_val / beacon_factor;
-
- return cpu_to_le16(new_val);
-}
-
-static void iwl3945_setup_rxon_timing(struct iwl_priv *priv)
-{
- u64 interval_tm_unit;
- u64 tsf, result;
- unsigned long flags;
- struct ieee80211_conf *conf = NULL;
- u16 beacon_int = 0;
-
- conf = ieee80211_get_hw_conf(priv->hw);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp);
- priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
-
- tsf = priv->timestamp;
-
- beacon_int = priv->beacon_int;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (priv->iw_mode == NL80211_IFTYPE_STATION) {
- if (beacon_int == 0) {
- priv->rxon_timing.beacon_interval = cpu_to_le16(100);
- priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
- } else {
- priv->rxon_timing.beacon_interval =
- cpu_to_le16(beacon_int);
- priv->rxon_timing.beacon_interval =
- iwl3945_adjust_beacon_interval(
- le16_to_cpu(priv->rxon_timing.beacon_interval));
- }
-
- priv->rxon_timing.atim_window = 0;
- } else {
- priv->rxon_timing.beacon_interval =
- iwl3945_adjust_beacon_interval(
- priv->vif->bss_conf.beacon_int);
- /* TODO: we need to get atim_window from upper stack
- * for now we set to 0 */
- priv->rxon_timing.atim_window = 0;
- }
-
- interval_tm_unit =
- (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
- result = do_div(tsf, interval_tm_unit);
- priv->rxon_timing.beacon_init_val =
- cpu_to_le32((u32) ((u64) interval_tm_unit - result));
-
- IWL_DEBUG_ASSOC(priv,
- "beacon interval %d beacon timer %d beacon tim %d\n",
- le16_to_cpu(priv->rxon_timing.beacon_interval),
- le32_to_cpu(priv->rxon_timing.beacon_init_val),
- le16_to_cpu(priv->rxon_timing.atim_window));
-}
-
static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
struct iwl_cmd *cmd,
@@ -682,8 +612,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_TX(priv, "sequence nr = 0X%x \n",
le16_to_cpu(out_cmd->hdr.sequence));
IWL_DEBUG_TX(priv, "tx_flags = 0X%x \n", le32_to_cpu(tx->tx_flags));
- iwl_print_hex_dump(priv, IWL_DL_TX, tx, sizeof(*tx));
- iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx->hdr,
+ iwl_print_hex_dump(IWL_DL_TX, tx, sizeof(*tx));
+ iwl_print_hex_dump(IWL_DL_TX, (u8 *)tx->hdr,
ieee80211_hdrlen(fc));
/*
@@ -996,7 +926,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
unsigned long status = priv->status;
- IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s\n",
+ IWL_WARN(priv, "Card state received: HW:%s SW:%s\n",
(flags & HW_CARD_DISABLED) ? "Kill" : "On",
(flags & SW_CARD_DISABLED) ? "Kill" : "On");
@@ -1714,7 +1644,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & IWL_DL_ISR) {
+ if (iwl_debug_level & IWL_DL_ISR) {
/* just for debug */
inta_mask = iwl_read32(priv, CSR_INT_MASK);
IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
@@ -1733,7 +1663,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
/* Now service all interrupt bits discovered above. */
if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Microcode HW error detected. Restarting.\n");
+ IWL_ERR(priv, "Hardware error detected. Restarting.\n");
/* Tell the device to stop sending interrupts */
iwl_disable_interrupts(priv);
@@ -1749,7 +1679,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
}
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
/* NIC fires this, but we don't use it, redundant with WAKEUP */
if (inta & CSR_INT_BIT_SCD) {
IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
@@ -1828,7 +1758,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
iwl_enable_interrupts(priv);
#ifdef CONFIG_IWLWIFI_DEBUG
- if (priv->debug_level & (IWL_DL_ISR)) {
+ if (iwl_debug_level & (IWL_DL_ISR)) {
inta = iwl_read32(priv, CSR_INT);
inta_mask = iwl_read32(priv, CSR_INT_MASK);
inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
@@ -1844,7 +1774,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
u8 is_active, u8 n_probes,
struct iwl3945_scan_channel *scan_ch)
{
- const struct ieee80211_channel *channels = NULL;
+ struct ieee80211_channel *chan;
const struct ieee80211_supported_band *sband;
const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
@@ -1855,19 +1785,19 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
if (!sband)
return 0;
- channels = sband->channels;
-
active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
passive_dwell = iwl_get_passive_dwell_time(priv, band);
if (passive_dwell <= active_dwell)
passive_dwell = active_dwell + 1;
- for (i = 0, added = 0; i < sband->n_channels; i++) {
- if (channels[i].flags & IEEE80211_CHAN_DISABLED)
+ for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+
+ if (chan->band != band)
continue;
- scan_ch->channel = channels[i].hw_value;
+ scan_ch->channel = chan->hw_value;
ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
if (!is_channel_valid(ch_info)) {
@@ -1882,7 +1812,7 @@ static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
* and use long active_dwell time.
*/
if (!is_active || is_channel_passive(ch_info) ||
- (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
+ (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) {
scan_ch->type = 0; /* passive */
if (IWL_UCODE_API(priv->ucode_ver) == 1)
scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1);
@@ -2111,7 +2041,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
*/
static int iwl3945_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ const struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
/* firmware file name contains uCode/driver compatibility version */
@@ -2152,22 +2082,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
goto error;
/* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+ init_data_size =
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely
@@ -2208,12 +2140,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size +
init_data_size + boot_size) {
- IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n",
- ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %zd does not match expected size\n",
+ ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -2296,44 +2229,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ len = inst_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode instr len %zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len);
+ src += len;
+
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl3945_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ len = data_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode data len %zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len);
+ src += len;
/* Initialization instructions (3rd block) */
if (init_size) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = init_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) init instr len %zd\n", len);
memcpy(priv->ucode_init.v_addr, src, len);
+ src += len;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = init_data_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) init data len %zd\n", len);
memcpy(priv->ucode_init_data.v_addr, src, len);
+ src += len;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ len = boot_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) boot instr len %zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
@@ -3066,7 +2999,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
iwlcore_commit_rxon(priv);
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl3945_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing), &priv->rxon_timing);
if (rc)
@@ -3261,7 +3194,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
/* RXON Timing */
memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
- iwl3945_setup_rxon_timing(priv);
+ iwl_setup_rxon_timing(priv);
rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
sizeof(priv->rxon_timing),
&priv->rxon_timing);
@@ -3375,13 +3308,15 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
* used for controlling the debug level.
*
* See the level definitions in iwl for details.
+ *
+ * FIXME This file can be deprecated as the module parameter is
+ * writable and users can thus also change the debug level
+ * using the /sys/module/iwl3945/parameters/debug file.
*/
static ssize_t show_debug_level(struct device *d,
struct device_attribute *attr, char *buf)
{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- return sprintf(buf, "0x%08X\n", priv->debug_level);
+ return sprintf(buf, "0x%08X\n", iwl_debug_level);
}
static ssize_t store_debug_level(struct device *d,
struct device_attribute *attr,
@@ -3395,7 +3330,7 @@ static ssize_t store_debug_level(struct device *d,
if (ret)
IWL_INFO(priv, "%s is not in hex or decimal form.\n", buf);
else
- priv->debug_level = val;
+ iwl_debug_level = val;
return strnlen(buf, count);
}
@@ -4017,15 +3952,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv = hw->priv;
SET_IEEE80211_DEV(hw, &pdev->dev);
- if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) ||
- (iwl3945_mod_params.num_of_queues < IWL39_MIN_NUM_QUEUES)) {
- IWL_ERR(priv,
- "invalid queues_num, should be between %d and %d\n",
- IWL39_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
- err = -EINVAL;
- goto out_ieee80211_free_hw;
- }
-
/*
* Disabling hardware scan means that mac80211 will perform scans
* "the hard way", rather than using device's scan.
@@ -4042,7 +3968,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->inta_mask = CSR_INI_SET_MASK;
#ifdef CONFIG_IWLWIFI_DEBUG
- priv->debug_level = iwl3945_mod_params.debug;
atomic_set(&priv->restrict_refcnt, 0);
#endif
@@ -4338,14 +4263,12 @@ MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
module_param_named(swcrypto, iwl3945_mod_params.sw_crypto, int, 0444);
MODULE_PARM_DESC(swcrypto,
"using software crypto (default 1 [software])\n");
-module_param_named(debug, iwl3945_mod_params.debug, uint, 0444);
+#ifdef CONFIG_IWLWIFI_DEBUG
+module_param_named(debug, iwl_debug_level, uint, 0644);
MODULE_PARM_DESC(debug, "debug output mask");
+#endif
module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, 0444);
MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
-
-module_param_named(queues_num, iwl3945_mod_params.num_of_queues, int, 0444);
-MODULE_PARM_DESC(queues_num, "number of hw queues.");
-
module_param_named(fw_restart3945, iwl3945_mod_params.restart_fw, int, 0444);
MODULE_PARM_DESC(fw_restart3945, "restart firmware in case of error");
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index 96f714e6e12..3f5a08fa401 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
@@ -130,6 +131,133 @@ static struct ieee80211_supported_band iwm_band_5ghz = {
.n_bitrates = iwm_a_rates_size,
};
+static int iwm_key_init(struct iwm_key *key, u8 key_index,
+ const u8 *mac_addr, struct key_params *params)
+{
+ key->hdr.key_idx = key_index;
+ if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
+ key->hdr.multicast = 1;
+ memset(key->hdr.mac, 0xff, ETH_ALEN);
+ } else {
+ key->hdr.multicast = 0;
+ memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
+ }
+
+ if (params) {
+ if (params->key_len > WLAN_MAX_KEY_LEN ||
+ params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
+ return -EINVAL;
+
+ key->cipher = params->cipher;
+ key->key_len = params->key_len;
+ key->seq_len = params->seq_len;
+ memcpy(key->key, params->key, key->key_len);
+ memcpy(key->seq, params->seq, key->seq_len);
+ }
+
+ return 0;
+}
+
+static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+ int ret;
+
+ IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
+
+ memset(key, 0, sizeof(struct iwm_key));
+ ret = iwm_key_init(key, key_index, mac_addr, params);
+ if (ret < 0) {
+ IWM_ERR(iwm, "Invalid key_params\n");
+ return ret;
+ }
+
+ return iwm_set_key(iwm, 0, key);
+}
+
+static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr, void *cookie,
+ void (*callback)(void *cookie,
+ struct key_params*))
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+ struct key_params params;
+
+ IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
+
+ memset(&params, 0, sizeof(params));
+
+ params.cipher = key->cipher;
+ params.key_len = key->key_len;
+ params.seq_len = key->seq_len;
+ params.seq = key->seq;
+ params.key = key->key;
+
+ callback(cookie, &params);
+
+ return key->key_len ? 0 : -ENOENT;
+}
+
+
+static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
+ u8 key_index, const u8 *mac_addr)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+ struct iwm_key *key = &iwm->keys[key_index];
+
+ if (!iwm->keys[key_index].key_len) {
+ IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
+ return 0;
+ }
+
+ if (key_index == iwm->default_key)
+ iwm->default_key = -1;
+
+ return iwm_set_key(iwm, 1, key);
+}
+
+static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
+ struct net_device *ndev,
+ u8 key_index)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
+
+ if (!iwm->keys[key_index].key_len) {
+ IWM_ERR(iwm, "Key %d not used\n", key_index);
+ return -EINVAL;
+ }
+
+ iwm->default_key = key_index;
+
+ return iwm_set_tx_key(iwm, key_index);
+}
+
+int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct iwm_priv *iwm = ndev_to_iwm(ndev);
+
+ if (memcmp(mac, iwm->bssid, ETH_ALEN))
+ return -ENOENT;
+
+ sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->txrate.legacy = iwm->rate * 10;
+
+ if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
+ sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->signal = iwm->wstats.qual.level;
+ }
+
+ return 0;
+}
+
+
int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
{
struct wiphy *wiphy = iwm_to_wiphy(iwm);
@@ -167,20 +295,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
return 0;
}
-static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex,
+static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
+ struct net_device *ndev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *ndev;
struct wireless_dev *wdev;
struct iwm_priv *iwm;
u32 old_mode;
- /* we're under RTNL */
- ndev = __dev_get_by_index(&init_net, ifindex);
- if (!ndev)
- return -ENODEV;
-
wdev = ndev->ieee80211_ptr;
iwm = ndev_to_iwm(ndev);
old_mode = iwm->conf.mode;
@@ -329,12 +452,245 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return 0;
}
+static int iwm_set_auth_type(struct iwm_priv *iwm,
+ enum nl80211_auth_type sme_auth_type)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ switch (sme_auth_type) {
+ case NL80211_AUTHTYPE_AUTOMATIC:
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
+ *auth_type = UMAC_AUTH_TYPE_OPEN;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
+ IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ } else {
+ IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ }
+
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
+{
+ if (!wpa_version) {
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
+ return 0;
+ }
+
+ if (wpa_version & NL80211_WPA_VERSION_2)
+ iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
+
+ if (wpa_version & NL80211_WPA_VERSION_1)
+ iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
+
+ return 0;
+}
+
+static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
+{
+ u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
+ &iwm->umac_profile->sec.mcast_cipher;
+
+ if (!cipher) {
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ return 0;
+ }
+
+ switch (cipher) {
+ case IW_AUTH_CIPHER_NONE:
+ *profile_cipher = UMAC_CIPHER_TYPE_NONE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
+ break;
+ default:
+ IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
+{
+ u8 *auth_type = &iwm->umac_profile->sec.auth_type;
+
+ IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
+
+ if (key_mgt == WLAN_AKM_SUITE_8021X)
+ *auth_type = UMAC_AUTH_TYPE_8021X;
+ else if (key_mgt == WLAN_AKM_SUITE_PSK) {
+ if (iwm->umac_profile->sec.flags &
+ (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
+ *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
+ else
+ *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
+ } else {
+ IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ struct ieee80211_channel *chan = sme->channel;
+ int ret;
+
+ if (!test_bit(IWM_STATUS_READY, &iwm->status))
+ return -EIO;
+
+ if (!sme->ssid)
+ return -EINVAL;
+
+ if (chan)
+ iwm->channel =
+ ieee80211_frequency_to_channel(chan->center_freq);
+
+ iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
+ memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
+
+ if (sme->bssid) {
+ IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
+ memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
+ iwm->umac_profile->bss_num = 1;
+ } else {
+ memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
+ iwm->umac_profile->bss_num = 0;
+ }
+
+ ret = iwm_set_auth_type(iwm, sme->auth_type);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
+ true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
+ if (ret < 0)
+ return ret;
+
+ if (sme->crypto.n_akm_suites) {
+ ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return iwm_send_mlme_profile(iwm);
+}
+
+static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
+
+ if (iwm->umac_profile_active)
+ return iwm_invalidate_mlme_profile(iwm);
+
+ return 0;
+}
+
+static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
+ enum tx_power_setting type, int dbm)
+{
+ switch (type) {
+ case TX_POWER_AUTOMATIC:
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+
+ *dbm = iwm->txpower;
+
+ return 0;
+}
+
+static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
+ u32 power_index;
+
+ if (enabled)
+ power_index = IWM_POWER_INDEX_DEFAULT;
+ else
+ power_index = IWM_POWER_INDEX_MIN;
+
+ if (power_index == iwm->conf.power_index)
+ return 0;
+
+ iwm->conf.power_index = power_index;
+
+ return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_POWER_INDEX, iwm->conf.power_index);
+}
+
static struct cfg80211_ops iwm_cfg80211_ops = {
.change_virtual_intf = iwm_cfg80211_change_iface,
+ .add_key = iwm_cfg80211_add_key,
+ .get_key = iwm_cfg80211_get_key,
+ .del_key = iwm_cfg80211_del_key,
+ .set_default_key = iwm_cfg80211_set_default_key,
+ .get_station = iwm_cfg80211_get_station,
.scan = iwm_cfg80211_scan,
.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+ .connect = iwm_cfg80211_connect,
+ .disconnect = iwm_cfg80211_disconnect,
.join_ibss = iwm_cfg80211_join_ibss,
.leave_ibss = iwm_cfg80211_leave_ibss,
+ .set_tx_power = iwm_cfg80211_set_txpower,
+ .get_tx_power = iwm_cfg80211_get_txpower,
+ .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
+};
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
};
struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
@@ -379,6 +735,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
ret = wiphy_register(wdev->wiphy);
if (ret < 0) {
dev_err(dev, "Couldn't register wiphy device\n");
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 834a7f544e5..0d6637005f4 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -70,14 +70,27 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm,
int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
bool resp)
{
+ struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload;
struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
struct iwm_umac_cmd umac_cmd;
+ int ret;
+ u8 oid = hdr->oid;
umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
umac_cmd.resp = resp;
- return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
- payload, payload_size);
+ ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
+ payload, payload_size);
+
+ if (resp) {
+ ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue,
+ test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
+ 3 * HZ);
+
+ return ret ? 0 : -EBUSY;
+ }
+
+ return ret;
}
static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] =
@@ -106,7 +119,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] =
{4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
{3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
{5, 5, 0, COEX_CALIBRATION_FLAGS},
- {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
+ {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
{5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
{4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
{4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
@@ -331,8 +344,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
return ret;
}
-int iwm_send_umac_config(struct iwm_priv *iwm,
- __le32 reset_flags)
+int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
{
int ret;
@@ -360,6 +372,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
+ CFG_WIRELESS_MODE,
+ iwm->conf.wireless_mode);
+ if (ret < 0)
+ return ret;
+
+ ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
CFG_COEX_MODE, iwm->conf.coexist_mode);
if (ret < 0)
return ret;
@@ -401,7 +419,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
return ret;
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_PM_CTRL_FLAGS, 0x30001);
+ CFG_PM_CTRL_FLAGS, 0x1);
if (ret < 0)
return ret;
@@ -461,8 +479,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
target_cmd.eop = 1;
ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
- if (ret < 0)
+ if (ret < 0) {
IWM_ERR(iwm, "Couldn't send READ command\n");
+ return ret;
+ }
/* When succeding, the send_target routine returns the seq number */
seq_num = ret;
@@ -482,7 +502,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
kfree(cmd);
- return ret;
+ return 0;
}
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
@@ -492,7 +512,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
mac_align, sizeof(mac_align));
- if (ret < 0)
+ if (ret)
return ret;
if (is_valid_ether_addr(mac_align))
@@ -510,9 +530,6 @@ int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
{
struct iwm_umac_tx_key_id tx_key_id;
- if (!iwm->default_key || !iwm->default_key->in_use)
- return -EINVAL;
-
tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
sizeof(struct iwm_umac_wifi_if));
@@ -555,10 +572,9 @@ static int iwm_check_profile(struct iwm_priv *iwm)
return 0;
}
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
- struct iwm_key *key)
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
{
- int ret;
+ int ret = 0;
u8 cmd[64], *sta_addr, *key_data, key_len;
s8 key_idx;
u16 cmd_size = 0;
@@ -568,15 +584,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
- if (set_tx_key)
- iwm->default_key = key;
-
- /*
- * We check if our current profile is valid.
- * If not, we dont push the key, we just cache them,
- * so that with the next siwsessid call, the keys
- * will be actually pushed.
- */
if (!remove) {
ret = iwm_check_profile(iwm);
if (ret < 0)
@@ -589,8 +596,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_idx = key->hdr.key_idx;
if (!remove) {
- IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n",
- key_idx, set_tx_key);
+ IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
@@ -602,8 +608,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
iwm->umac_profile->sec.auth_type,
iwm->umac_profile->sec.flags);
- switch (key->alg) {
- case UMAC_CIPHER_TYPE_WEP_40:
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
wep40->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
@@ -617,7 +623,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
cmd_size = sizeof(struct iwm_umac_key_wep40);
break;
- case UMAC_CIPHER_TYPE_WEP_104:
+ case WLAN_CIPHER_SUITE_WEP104:
wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
wep104->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
@@ -631,7 +637,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
cmd_size = sizeof(struct iwm_umac_key_wep104);
break;
- case UMAC_CIPHER_TYPE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP:
key_hdr->key_idx++;
ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
ccmp->hdr.buf_size =
@@ -643,13 +649,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
memcpy(ccmp->key, key_data, key_len);
- if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- memcpy(ccmp->iv_count, key->rx_seq, 6);
+ if (key->seq_len)
+ memcpy(ccmp->iv_count, key->seq, key->seq_len);
cmd_size = sizeof(struct iwm_umac_key_ccmp);
break;
- case UMAC_CIPHER_TYPE_TKIP:
+ case WLAN_CIPHER_SUITE_TKIP:
key_hdr->key_idx++;
tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
tkip->hdr.buf_size =
@@ -666,8 +672,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
IWM_TKIP_MIC_SIZE);
- if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- memcpy(ccmp->iv_count, key->rx_seq, 6);
+ if (key->seq_len)
+ memcpy(ccmp->iv_count, key->seq, key->seq_len);
cmd_size = sizeof(struct iwm_umac_key_tkip);
break;
@@ -676,8 +682,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
return -ENOTSUPP;
}
- if ((key->alg == UMAC_CIPHER_TYPE_CCMP) ||
- (key->alg == UMAC_CIPHER_TYPE_TKIP))
+ if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
+ (key->cipher == WLAN_CIPHER_SUITE_CCMP))
/*
* UGLY_UGLY_UGLY
* Copied HACK from the MWG driver.
@@ -688,23 +694,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
schedule_timeout_interruptible(usecs_to_jiffies(300));
ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
- if (ret < 0)
- goto err;
-
- /*
- * We need a default key only if it is set and
- * if we're doing WEP.
- */
- if (iwm->default_key == key &&
- ((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
- (key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
- ret = iwm_set_tx_key(iwm, key_idx);
- if (ret < 0)
- goto err;
- }
} else {
struct iwm_umac_key_remove key_remove;
+ IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);
+
key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
key_remove.hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
@@ -715,23 +709,19 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
ret = iwm_send_wifi_if_cmd(iwm, &key_remove,
sizeof(struct iwm_umac_key_remove),
1);
- if (ret < 0)
+ if (ret)
return ret;
- iwm->keys[key_idx].in_use = 0;
+ iwm->keys[key_idx].key_len = 0;
}
- return 0;
-
- err:
- kfree(key);
return ret;
}
int iwm_send_mlme_profile(struct iwm_priv *iwm)
{
- int ret, i;
+ int ret;
struct iwm_umac_profile profile;
memcpy(&profile, iwm->umac_profile, sizeof(profile));
@@ -741,45 +731,18 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
sizeof(struct iwm_umac_wifi_if));
ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
- if (ret < 0) {
+ if (ret) {
IWM_ERR(iwm, "Send profile command failed\n");
return ret;
}
- /* Wait for the profile to be active */
- ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- iwm->umac_profile_active == 1,
- 3 * HZ);
- if (!ret)
- return -EBUSY;
-
-
- for (i = 0; i < IWM_NUM_KEYS; i++)
- if (iwm->keys[i].in_use) {
- int default_key = 0;
- struct iwm_key *key = &iwm->keys[i];
-
- if (key == iwm->default_key)
- default_key = 1;
-
- /* Wait for the profile before sending the keys */
- wait_event_interruptible_timeout(iwm->mlme_queue,
- (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
- test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
- 3 * HZ);
-
- ret = iwm_set_key(iwm, 0, default_key, key);
- if (ret < 0)
- return ret;
- }
-
return 0;
}
int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
{
- int ret;
struct iwm_umac_invalidate_profile invalid;
+ int ret;
invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
invalid.hdr.buf_size =
@@ -789,16 +752,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
invalid.reason = WLAN_REASON_UNSPECIFIED;
ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
- if (ret < 0)
+ if (ret)
return ret;
ret = wait_event_interruptible_timeout(iwm->mlme_queue,
- (iwm->umac_profile_active == 0),
- 2 * HZ);
- if (!ret)
- return -EBUSY;
+ (iwm->umac_profile_active == 0), 2 * HZ);
- return 0;
+ return ret ? 0 : -EBUSY;
}
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags)
@@ -881,7 +841,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
}
ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
- if (ret < 0) {
+ if (ret) {
IWM_ERR(iwm, "Couldn't send scan request\n");
return ret;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 36b13a13059..e24d5b63399 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -106,8 +106,7 @@ enum {
CFG_TLC_SPATIAL_STREAM_SUPPORTED,
CFG_TLC_RETRY_PER_RATE,
CFG_TLC_RETRY_PER_HT_RATE,
- CFG_TLC_FIXED_RATE,
- CFG_TLC_FIXED_RATE_FLAGS,
+ CFG_TLC_FIXED_MCS,
CFG_TLC_CONTROL_FLAGS,
CFG_TLC_SR_MIN_FAIL,
CFG_TLC_SR_MIN_PASS,
@@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list {
/* Wireless mode */
#define WIRELESS_MODE_11A 0x1
#define WIRELESS_MODE_11G 0x2
+#define WIRELESS_MODE_11N 0x4
#define UMAC_PROFILE_EX_IE_REQUIRED 0x1
#define UMAC_PROFILE_QOS_ALLOWED 0x2
@@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm);
int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
-int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
- struct iwm_key *key);
+int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c
index 0f34b84fd2e..365910fbe01 100644
--- a/drivers/net/wireless/iwmc3200wifi/eeprom.c
+++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c
@@ -156,10 +156,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm)
return -ENOMEM;
for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET))
- break;
-#endif
ret = iwm_eeprom_read(iwm, i);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n",
diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c
index ec1a15a5a0e..0f32cab9ced 100644
--- a/drivers/net/wireless/iwmc3200wifi/fw.c
+++ b/drivers/net/wireless/iwmc3200wifi/fw.c
@@ -275,6 +275,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name)
*/
int iwm_load_fw(struct iwm_priv *iwm)
{
+ unsigned long init_calib_map, periodic_calib_map;
int ret;
/* We first start downloading the UMAC */
@@ -315,23 +316,19 @@ int iwm_load_fw(struct iwm_priv *iwm)
return ret;
}
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map);
- clear_bit(PHY_CALIBRATE_RX_IQ_CMD,
- &iwm->conf.periodic_calib_map);
- }
-#endif
+ init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK;
+ periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map);
+
/* Read RX IQ calibration result from EEPROM */
- if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) {
+ if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) {
iwm_store_rxiq_calib_result(iwm);
set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
}
iwm_send_prio_table(iwm);
- iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map);
+ iwm_send_init_calib_cfg(iwm, init_calib_map);
- while (iwm->calib_done_map != iwm->conf.init_calib_map) {
+ while (iwm->calib_done_map != init_calib_map) {
ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
if (ret) {
@@ -340,7 +337,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
}
IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
"0x%lx, requested calibrations: 0x%lx\n",
- iwm->calib_done_map, iwm->conf.init_calib_map);
+ iwm->calib_done_map, init_calib_map);
}
/* Handle LMAC CALIBRATION_COMPLETE notification */
@@ -378,7 +375,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
iwm_send_prio_table(iwm);
iwm_send_calib_results(iwm);
- iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map);
+ iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
return 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index ee127fe4f43..c430418248b 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -105,9 +105,9 @@
#include "umac.h"
#include "debug.h"
-static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
- struct iwm_nonwifi_cmd *cmd,
- struct iwm_udma_nonwifi_cmd *udma_cmd)
+static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
+ struct iwm_nonwifi_cmd *cmd,
+ struct iwm_udma_nonwifi_cmd *udma_cmd)
{
INIT_LIST_HEAD(&cmd->pending);
@@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->seq_num = iwm->nonwifi_seq_num;
udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
- cmd->seq_num = iwm->nonwifi_seq_num++;
+ iwm->nonwifi_seq_num++;
iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
if (udma_cmd->resp)
@@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
cmd->buf.len = 0;
memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
+
+ return cmd->seq_num;
}
u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
@@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
const void *payload)
{
struct iwm_nonwifi_cmd *cmd;
- int ret;
+ int ret, seq_num;
cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
if (!cmd) {
@@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
return -ENOMEM;
}
- iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
+ seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
@@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
if (ret < 0)
return ret;
- return cmd->seq_num;
+ return seq_num;
}
static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr,
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 77c339f8516..2175a481d2f 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -52,8 +52,6 @@
#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
#define IWM_AUTHOR "<ilw@linux.intel.com>"
-#define CONFIG_IWM_B0_HW_SUPPORT 1
-
#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX
#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA
#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW
@@ -65,8 +63,7 @@
struct iwm_conf {
u32 sdio_ior_timeout;
- unsigned long init_calib_map;
- unsigned long periodic_calib_map;
+ unsigned long calib_map;
bool reset_on_fatal_err;
bool auto_connect;
bool wimax_not_present;
@@ -87,9 +84,6 @@ struct iwm_conf {
u8 ibss_channel;
u8 mac_addr[ETH_ALEN];
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- bool hw_b0;
-#endif
};
enum {
@@ -162,13 +156,11 @@ struct iwm_umac_key_hdr {
struct iwm_key {
struct iwm_umac_key_hdr hdr;
- u8 in_use;
- u8 alg;
- u32 flags;
- u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE];
- u8 key_len;
- u8 key[32];
+ u32 cipher;
+ u8 key[WLAN_MAX_KEY_LEN];
+ u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
+ int key_len;
+ int seq_len;
};
#define IWM_RX_ID_HASH 0xff
@@ -186,10 +178,6 @@ struct iwm_key {
#define IWM_STATUS_ASSOCIATING 3
#define IWM_STATUS_ASSOCIATED 4
-#define IWM_RADIO_RFKILL_OFF 0
-#define IWM_RADIO_RFKILL_HW 1
-#define IWM_RADIO_RFKILL_SW 2
-
struct iwm_tx_queue {
int id;
struct sk_buff_head queue;
@@ -223,7 +211,6 @@ struct iwm_priv {
struct iwm_conf conf;
unsigned long status;
- unsigned long radio;
struct list_head pending_notif;
wait_queue_head_t notif_queue;
@@ -242,6 +229,7 @@ struct iwm_priv {
u8 bssid[ETH_ALEN];
u8 channel;
u16 rate;
+ u32 txpower;
struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
struct list_head bss_list;
@@ -276,7 +264,10 @@ struct iwm_priv {
struct iwm_tx_queue txq[IWM_TX_QUEUES];
struct iwm_key keys[IWM_NUM_KEYS];
- struct iwm_key *default_key;
+ s8 default_key;
+
+ DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
+ wait_queue_head_t wifi_ntfy_queue;
wait_queue_head_t mlme_queue;
@@ -289,7 +280,11 @@ struct iwm_priv {
struct timer_list watchdog;
struct work_struct reset_worker;
struct mutex mutex;
- struct rfkill *rfkill;
+
+ u8 *req_ie;
+ int req_ie_len;
+ u8 *resp_ie;
+ int resp_ie_len;
char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index db2e5eea189..19213e165f5 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -396,6 +396,10 @@ enum {
CALIBRATION_CMD_NUM,
};
+#define IWM_CALIB_MAP_INIT_MSK 0xFFFF
+#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16)
+#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24)
+
struct iwm_lmac_calib_hdr {
u8 opcode;
u8 first_grp;
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 8be206d5822..cf2574442b5 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -53,11 +53,7 @@
static struct iwm_conf def_iwm_conf = {
.sdio_ior_timeout = 5000,
- .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
- BIT(PHY_CALIBRATE_LO_CMD) |
- BIT(PHY_CALIBRATE_TX_IQ_CMD) |
- BIT(PHY_CALIBRATE_RX_IQ_CMD),
- .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
+ .calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
BIT(PHY_CALIBRATE_LO_CMD) |
BIT(PHY_CALIBRATE_TX_IQ_CMD) |
BIT(PHY_CALIBRATE_RX_IQ_CMD) |
@@ -191,6 +187,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
INIT_LIST_HEAD(&iwm->pending_notif);
init_waitqueue_head(&iwm->notif_queue);
init_waitqueue_head(&iwm->nonwifi_queue);
+ init_waitqueue_head(&iwm->wifi_ntfy_queue);
init_waitqueue_head(&iwm->mlme_queue);
memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
spin_lock_init(&iwm->tx_credit.lock);
@@ -229,7 +226,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
for (i = 0; i < IWM_NUM_KEYS; i++)
memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
- iwm->default_key = NULL;
+ iwm->default_key = -1;
init_timer(&iwm->watchdog);
iwm->watchdog.function = iwm_watchdog;
@@ -500,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm)
memset(wstats, 0, sizeof(struct iw_statistics));
wstats->qual.updated = IW_QUAL_ALL_INVALID;
+ kfree(iwm->req_ie);
+ iwm->req_ie = NULL;
+ iwm->req_ie_len = 0;
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = NULL;
+ iwm->resp_ie_len = 0;
+
del_timer_sync(&iwm->watchdog);
}
@@ -518,13 +522,6 @@ static int iwm_channels_init(struct iwm_priv *iwm)
{
int ret;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (iwm->conf.hw_b0) {
- IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n");
- return 0;
- }
-#endif
-
ret = iwm_send_umac_channel_list(iwm);
if (ret) {
IWM_ERR(iwm, "Send channel list failed\n");
@@ -642,19 +639,10 @@ int __iwm_up(struct iwm_priv *iwm)
}
}
- iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
- GFP_KERNEL);
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
- goto err_fw;
- }
-
- iwm_init_default_profile(iwm, iwm->umac_profile);
-
ret = iwm_channels_init(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't init channels\n");
- goto err_profile;
+ goto err_fw;
}
/* Set the READY bit to indicate interface is brought up successfully */
@@ -662,10 +650,6 @@ int __iwm_up(struct iwm_priv *iwm)
return 0;
- err_profile:
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
-
err_fw:
iwm_eeprom_exit(iwm);
@@ -704,11 +688,10 @@ int __iwm_down(struct iwm_priv *iwm)
clear_bit(IWM_STATUS_READY, &iwm->status);
iwm_eeprom_exit(iwm);
- kfree(iwm->umac_profile);
- iwm->umac_profile = NULL;
iwm_bss_list_clean(iwm);
-
- iwm->default_key = NULL;
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+ iwm->umac_profile_active = false;
+ iwm->default_key = -1;
iwm->core_enabled = 0;
ret = iwm_bus_disable(iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index bf294e41753..93cc1b3e7f4 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -48,29 +48,22 @@
#include <linux/netdevice.h>
#include "iwm.h"
+#include "commands.h"
#include "cfg80211.h"
#include "debug.h"
static int iwm_open(struct net_device *ndev)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- int ret = 0;
-
- if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
- ret = iwm_up(iwm);
- return ret;
+ return iwm_up(iwm);
}
static int iwm_stop(struct net_device *ndev)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
- int ret = 0;
-
- if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
- ret = iwm_down(iwm);
- return ret;
+ return iwm_down(iwm);
}
/*
@@ -133,8 +126,20 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
+ iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
+ GFP_KERNEL);
+ if (!iwm->umac_profile) {
+ dev_err(dev, "Couldn't alloc memory for profile\n");
+ goto out_profile;
+ }
+
+ iwm_init_default_profile(iwm, iwm->umac_profile);
+
return iwm;
+ out_profile:
+ free_netdev(ndev);
+
out_priv:
iwm_priv_deinit(iwm);
@@ -150,6 +155,8 @@ void iwm_if_free(struct iwm_priv *iwm)
free_netdev(iwm_to_ndev(iwm));
iwm_priv_deinit(iwm);
+ kfree(iwm->umac_profile);
+ iwm->umac_profile = NULL;
iwm_wdev_free(iwm);
}
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index d73cf96c6dc..86079a187ee 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf,
error = (struct iwm_umac_notif_error *)buf;
fw_err = &error->err;
-
IWM_ERR(iwm, "%cMAC FW ERROR:\n",
(le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category));
@@ -143,17 +142,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size,
struct iwm_wifi_cmd *cmd)
{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct iwm_umac_notif_init_complete *init_complete =
(struct iwm_umac_notif_init_complete *)(buf);
u16 status = le16_to_cpu(init_complete->status);
+ bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR);
- if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) {
+ if (blocked)
IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
- set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- } else {
+ else
IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
- clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- }
+
+ wiphy_rfkill_set_hw_state(wiphy, blocked);
return 0;
}
@@ -218,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
(buf + sizeof(struct iwm_umac_wifi_in_hdr));
hdr = (struct iwm_umac_wifi_in_hdr *)buf;
- IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
+ IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
- IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n",
- le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
- IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
- IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n",
- le16_to_cpu(tx_resp->retry_cnt));
- IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
- IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n",
- le16_to_cpu(tx_resp->byte_cnt));
- IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
+ IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
+ le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
+ IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
+ IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
+ le16_to_cpu(tx_resp->retry_cnt));
+ IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
+ IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
+ le16_to_cpu(tx_resp->byte_cnt));
+ IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
return 0;
}
@@ -418,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
if (IS_ERR(ticket_node))
return PTR_ERR(ticket_node);
- IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n",
- ticket->id);
+ IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
+ ticket->id);
list_add_tail(&ticket_node->node, &iwm->rx_tickets);
/*
@@ -454,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
u16 id, buf_offset;
u32 packet_size;
- IWM_DBG_NTF(iwm, DBG, "\n");
+ IWM_DBG_RX(iwm, DBG, "\n");
wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
- IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
- wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
+ IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
+ wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
@@ -503,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
{
struct iwm_umac_notif_assoc_complete *complete =
(struct iwm_umac_notif_assoc_complete *)buf;
- union iwreq_data wrqu;
IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
complete->bssid, complete->status);
- memset(&wrqu, 0, sizeof(wrqu));
-
clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
switch (le32_to_cpu(complete->status)) {
@@ -520,7 +517,14 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
iwm_link_on(iwm);
- memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN);
+ if (iwm->conf.mode == UMAC_MODE_IBSS)
+ goto ibss;
+
+ cfg80211_connect_result(iwm_to_ndev(iwm),
+ complete->bssid,
+ iwm->req_ie, iwm->req_ie_len,
+ iwm->resp_ie, iwm->resp_ie_len,
+ WLAN_STATUS_SUCCESS, GFP_KERNEL);
break;
case UMAC_ASSOC_COMPLETE_FAILURE:
clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -528,18 +532,22 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
iwm->channel = 0;
iwm_link_off(iwm);
+
+ if (iwm->conf.mode == UMAC_MODE_IBSS)
+ goto ibss;
+
+ cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE,
+ GFP_KERNEL);
default:
break;
}
- if (iwm->conf.mode == UMAC_MODE_IBSS) {
- cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
- return 0;
- }
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
+ return 0;
+ ibss:
+ cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
return 0;
}
@@ -769,37 +777,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
struct iwm_umac_notif_mgt_frame *mgt_frame =
- (struct iwm_umac_notif_mgt_frame *)buf;
+ (struct iwm_umac_notif_mgt_frame *)buf;
struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
u8 *ie;
- unsigned int event;
- union iwreq_data wrqu;
IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
le16_to_cpu(mgt_frame->len));
if (ieee80211_is_assoc_req(mgt->frame_control)) {
ie = mgt->u.assoc_req.variable;;
- event = IWEVASSOCREQIE;
+ iwm->req_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->req_ie);
+ iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
+ iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
ie = mgt->u.reassoc_req.variable;;
- event = IWEVASSOCREQIE;
+ iwm->req_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->req_ie);
+ iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
+ iwm->req_ie_len, GFP_KERNEL);
} else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
ie = mgt->u.assoc_resp.variable;;
- event = IWEVASSOCRESPIE;
+ iwm->resp_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
+ iwm->resp_ie_len, GFP_KERNEL);
} else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
ie = mgt->u.reassoc_resp.variable;;
- event = IWEVASSOCRESPIE;
+ iwm->resp_ie_len =
+ le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
+ kfree(iwm->resp_ie);
+ iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
+ iwm->resp_ie_len, GFP_KERNEL);
} else {
IWM_ERR(iwm, "Unsupported management frame");
return 0;
}
- wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
-
- IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length);
- wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie);
-
return 0;
}
@@ -875,6 +892,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
/* UMAC passes rate info multiplies by 2 */
iwm->rate = max_rate >> 1;
}
+ iwm->txpower = le32_to_cpu(stats->tx_power);
wstats->status = 0;
@@ -922,13 +940,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf,
if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN)
return -EINVAL;
-#ifdef CONFIG_IWM_B0_HW_SUPPORT
- if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) {
- if (eeprom_proxy->buf[0] == 0xff)
- iwm->conf.hw_b0 = 1;
- }
-#endif
-
switch (hdr_type) {
case IWM_UMAC_CMD_EEPROM_TYPE_READ:
memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len);
@@ -993,12 +1004,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
(struct iwm_umac_wifi_if *)cmd->buf.payload;
IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
- "oid is %d\n", hdr->oid);
+ "oid is 0x%x\n", hdr->oid);
+
+ if (hdr->oid <= WIFI_IF_NTFY_MAX) {
+ set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
+ wake_up_interruptible(&iwm->wifi_ntfy_queue);
+ } else
+ return -EINVAL;
switch (hdr->oid) {
case UMAC_WIFI_IF_CMD_SET_PROFILE:
iwm->umac_profile_active = 1;
- wake_up_interruptible(&iwm->mlme_queue);
break;
default:
break;
@@ -1010,6 +1026,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
unsigned long buf_size, struct iwm_wifi_cmd *cmd)
{
+ struct wiphy *wiphy = iwm_to_wiphy(iwm);
struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
(buf + sizeof(struct iwm_umac_wifi_in_hdr));
u32 flags = le32_to_cpu(state->flags);
@@ -1018,10 +1035,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
- if (flags & IWM_CARD_STATE_HW_DISABLED)
- set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
- else
- clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
+ wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
return 0;
}
@@ -1362,13 +1376,13 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
skb->dev = iwm_to_ndev(iwm);
skb->protocol = eth_type_trans(skb, ndev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed = CHECKSUM_NONE;
memset(skb->cb, 0, sizeof(skb->cb));
ndev->stats.rx_packets++;
ndev->stats.rx_bytes += skb->len;
- if (netif_rx(skb) == NET_RX_DROP) {
+ if (netif_rx_ni(skb) == NET_RX_DROP) {
IWM_ERR(iwm, "Packet dropped\n");
ndev->stats.rx_dropped++;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c
index 916681837fd..8b1de84003c 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.c
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.c
@@ -65,6 +65,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/debugfs.h>
+#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
@@ -492,7 +493,8 @@ static void iwm_sdio_remove(struct sdio_func *func)
}
static const struct sdio_device_id iwm_sdio_ids[] = {
- { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) },
+ { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
+ SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) },
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
@@ -506,11 +508,7 @@ static struct sdio_driver iwm_sdio_driver = {
static int __init iwm_sdio_init_module(void)
{
- int ret;
-
- ret = sdio_register_driver(&iwm_sdio_driver);
-
- return ret;
+ return sdio_register_driver(&iwm_sdio_driver);
}
static void __exit iwm_sdio_exit_module(void)
diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h
index b3c156b08dd..aab6b6892e4 100644
--- a/drivers/net/wireless/iwmc3200wifi/sdio.h
+++ b/drivers/net/wireless/iwmc3200wifi/sdio.h
@@ -39,9 +39,6 @@
#ifndef __IWM_SDIO_H__
#define __IWM_SDIO_H__
-#define SDIO_VENDOR_ID_INTEL 0x89
-#define SDIO_DEVICE_ID_IWM 0x1403
-
#define IWM_SDIO_DATA_ADDR 0x0
#define IWM_SDIO_INTR_ENABLE_ADDR 0x14
#define IWM_SDIO_INTR_STATUS_ADDR 0x13
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index 4a95cce1f0a..c5a14ae3160 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr {
#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8
#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9
+#define WIFI_IF_NTFY_MAX 0xff
+
/* Notification structures */
struct iwm_umac_notif_wifi_if {
struct iwm_umac_wifi_in_hdr hdr;
@@ -613,6 +615,7 @@ struct iwm_umac_notif_alive {
} __attribute__ ((packed));
struct iwm_umac_notif_init_complete {
+ struct iwm_umac_wifi_in_hdr hdr;
__le16 status;
__le16 reserved;
} __attribute__ ((packed));
@@ -641,6 +644,11 @@ struct iwm_fw_error_hdr {
__le32 umac_status;
__le32 lmac_status;
__le32 sdio_status;
+ __le32 dbm_sample_ctrl;
+ __le32 dbm_buf_base;
+ __le32 dbm_buf_end;
+ __le32 dbm_buf_write_ptr;
+ __le32 dbm_buf_cycle_cnt;
} __attribute__ ((packed));
struct iwm_umac_notif_error {
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c
index 584c94d0f39..c3c90d5963b 100644
--- a/drivers/net/wireless/iwmc3200wifi/wext.c
+++ b/drivers/net/wireless/iwmc3200wifi/wext.c
@@ -21,31 +21,11 @@
*
*/
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
#include <linux/wireless.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
#include <net/cfg80211.h>
-#include <net/iw_handler.h>
#include "iwm.h"
-#include "umac.h"
#include "commands.h"
-#include "debug.h"
-
-static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iw_statistics *wstats = &iwm->wstats;
-
- if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- memset(wstats, 0, sizeof(struct iw_statistics));
- wstats->qual.updated = IW_QUAL_ALL_INVALID;
- }
-
- return wstats;
-}
static int iwm_wext_siwfreq(struct net_device *dev,
struct iw_request_info *info,
@@ -53,14 +33,12 @@ static int iwm_wext_siwfreq(struct net_device *dev,
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (freq->flags == IW_FREQ_AUTO)
- return 0;
-
- /* frequency/channel can only be set in IBSS mode */
- if (iwm->conf.mode != UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
+ return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+ default:
return -EOPNOTSUPP;
-
- return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
+ }
}
static int iwm_wext_giwfreq(struct net_device *dev,
@@ -69,13 +47,14 @@ static int iwm_wext_giwfreq(struct net_device *dev,
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
-
- freq->e = 0;
- freq->m = iwm->channel;
-
- return 0;
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
+ default:
+ return -EOPNOTSUPP;
+ }
}
static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
@@ -83,37 +62,14 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (is_zero_ether_addr(ap_addr->sa_data) ||
- is_broadcast_ether_addr(ap_addr->sa_data)) {
- IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
- iwm->umac_profile->bssid[0]);
- memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
- iwm->umac_profile->bss_num = 0;
- } else {
- IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
- ap_addr->sa_data);
- memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
- ETH_ALEN);
- iwm->umac_profile->bss_num = 1;
- }
-
- if (iwm->umac_profile_active) {
- if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
- return 0;
-
- iwm_invalidate_mlme_profile(iwm);
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
+ default:
+ return -EOPNOTSUPP;
}
-
- if (iwm->umac_profile->ssid.ssid_len)
- return iwm_send_mlme_profile(iwm);
-
- return 0;
}
static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
@@ -125,17 +81,10 @@ static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
case UMAC_MODE_BSS:
- if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
- ap_addr->sa_family = ARPHRD_ETHER;
- memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
- } else
- memset(&ap_addr->sa_data, 0, ETH_ALEN);
- break;
+ return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
default:
return -EOPNOTSUPP;
}
-
- return 0;
}
static int iwm_wext_siwessid(struct net_device *dev,
@@ -143,34 +92,15 @@ static int iwm_wext_siwessid(struct net_device *dev,
struct iw_point *data, char *ssid)
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- size_t len = data->length;
- int ret;
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- if (len > 0 && ssid[len - 1] == '\0')
- len--;
-
- if (iwm->umac_profile_active) {
- if (iwm->umac_profile->ssid.ssid_len == len &&
- !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
- return 0;
-
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
+ default:
+ return -EOPNOTSUPP;
}
-
- iwm->umac_profile->ssid.ssid_len = len;
- memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
-
- return iwm_send_mlme_profile(iwm);
}
static int iwm_wext_giwessid(struct net_device *dev,
@@ -179,480 +109,14 @@ static int iwm_wext_giwessid(struct net_device *dev,
{
struct iwm_priv *iwm = ndev_to_iwm(dev);
- if (iwm->conf.mode == UMAC_MODE_IBSS)
+ switch (iwm->conf.mode) {
+ case UMAC_MODE_IBSS:
return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
-
- if (!test_bit(IWM_STATUS_READY, &iwm->status))
- return -EIO;
-
- data->length = iwm->umac_profile->ssid.ssid_len;
- if (data->length) {
- memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
- data->flags = 1;
- } else
- data->flags = 0;
-
- return 0;
-}
-
-static struct iwm_key *
-iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
- struct iw_encode_ext *ext, u8 alg)
-{
- struct iwm_key *key = &iwm->keys[key_idx];
-
- memset(key, 0, sizeof(struct iwm_key));
- memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
- key->hdr.key_idx = key_idx;
- if (is_broadcast_ether_addr(ext->addr.sa_data))
- key->hdr.multicast = 1;
-
- key->in_use = in_use;
- key->flags = ext->ext_flags;
- key->alg = alg;
- key->key_len = ext->key_len;
- memcpy(key->key, ext->key, ext->key_len);
-
- return key;
-}
-
-static int iwm_wext_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *rate, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- rate->value = iwm->rate * 1000000;
-
- return 0;
-}
-
-static int iwm_wext_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key_buf)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iwm_key *uninitialized_var(key);
- int idx, i, uninitialized_var(alg), remove = 0, ret;
-
- IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
- IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
-
- if (!iwm->umac_profile) {
- IWM_ERR(iwm, "UMAC profile not allocated yet\n");
- return -ENODEV;
- }
-
- if (erq->length == WLAN_KEY_LEN_WEP40) {
- alg = UMAC_CIPHER_TYPE_WEP_40;
- iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
- iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
- } else if (erq->length == WLAN_KEY_LEN_WEP104) {
- alg = UMAC_CIPHER_TYPE_WEP_104;
- iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
- iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
- }
-
- if (erq->flags & IW_ENCODE_RESTRICTED)
- iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- else
- iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx == 0) {
- if (iwm->default_key)
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- else
- iwm->default_key = &iwm->keys[idx];
- } else if (idx < 1 || idx > 4) {
- return -EINVAL;
- } else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if (erq->length == 0) {
- if (!iwm->keys[idx].in_use)
- return -EINVAL;
- iwm->default_key = &iwm->keys[idx];
- }
-
- if (erq->length) {
- key = &iwm->keys[idx];
- memset(key, 0, sizeof(struct iwm_key));
- memset(key->hdr.mac, 0xff, ETH_ALEN);
- key->hdr.key_idx = idx;
- key->hdr.multicast = 1;
- key->in_use = !remove;
- key->alg = alg;
- key->key_len = erq->length;
- memcpy(key->key, key_buf, erq->length);
-
- IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
- idx, !!iwm->default_key);
- }
-
- if (remove) {
- if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
- int j;
- for (j = 0; j < IWM_NUM_KEYS; j++)
- if (iwm->keys[j].in_use) {
- struct iwm_key *k = &iwm->keys[j];
-
- k->in_use = 0;
- ret = iwm_set_key(iwm, remove, 0, k);
- if (ret < 0)
- return ret;
- }
-
- iwm->umac_profile->sec.ucast_cipher =
- UMAC_CIPHER_TYPE_NONE;
- iwm->umac_profile->sec.mcast_cipher =
- UMAC_CIPHER_TYPE_NONE;
- iwm->umac_profile->sec.auth_type =
- UMAC_AUTH_TYPE_OPEN;
-
- return 0;
- } else {
- key->in_use = 0;
- return iwm_set_key(iwm, remove, 0, key);
- }
- }
-
- /*
- * If we havent set a profile yet, we cant set keys.
- * Keys will be pushed after we're associated.
- */
- if (!iwm->umac_profile_active)
- return 0;
-
- /*
- * If there is a current active profile, but no
- * default key, it's not worth trying to associate again.
- */
- if (!iwm->default_key)
- return 0;
-
- /*
- * Here we have an active profile, but a key setting changed.
- * We thus have to invalidate the current profile, and push the
- * new one. Keys will be pushed when association takes place.
- */
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
-
- return iwm_send_mlme_profile(iwm);
-}
-
-static int iwm_wext_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int idx, i;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx < 1 || idx > 4) {
- idx = -1;
- if (!iwm->default_key) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_NOKEY;
- return 0;
- } else
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
-
- erq->flags = idx + 1;
-
- if (!iwm->keys[idx].in_use) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- memcpy(key, iwm->keys[idx].key,
- min_t(int, erq->length, iwm->keys[idx].key_len));
- erq->length = iwm->keys[idx].key_len;
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
- switch (iwm->umac_profile->sec.auth_type) {
- case UMAC_AUTH_TYPE_OPEN:
- erq->flags |= IW_ENCODE_OPEN;
- break;
- default:
- erq->flags |= IW_ENCODE_RESTRICTED;
- break;
- }
- }
-
- return 0;
-}
-
-static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
-{
- if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
- else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
- else
- iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
-
- return 0;
-}
-
-static int iwm_wext_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *wrq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- u32 power_index;
-
- if (wrq->disabled) {
- power_index = IWM_POWER_INDEX_MIN;
- goto set;
- } else
- power_index = IWM_POWER_INDEX_DEFAULT;
-
- switch (wrq->flags & IW_POWER_MODE) {
- case IW_POWER_ON:
- case IW_POWER_MODE:
- case IW_POWER_ALL_R:
- break;
- default:
- return -EINVAL;
- }
-
- set:
- if (power_index == iwm->conf.power_index)
- return 0;
-
- iwm->conf.power_index = power_index;
-
- return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
- CFG_POWER_INDEX, iwm->conf.power_index);
-}
-
-static int iwm_wext_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
-
- wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
-
- return 0;
-}
-
-static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
- *auth_type = UMAC_AUTH_TYPE_8021X;
- else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- else
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- } else {
- IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
-{
- u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
- &iwm->umac_profile->sec.mcast_cipher;
-
- switch (cipher) {
- case IW_AUTH_CIPHER_NONE:
- *profile_cipher = UMAC_CIPHER_TYPE_NONE;
- break;
- case IW_AUTH_CIPHER_WEP40:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
- break;
- case IW_AUTH_CIPHER_TKIP:
- *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_AUTH_CIPHER_CCMP:
- *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
- break;
- case IW_AUTH_CIPHER_WEP104:
- *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
- break;
- default:
- IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
-{
- u8 *auth_type = &iwm->umac_profile->sec.auth_type;
-
- switch (auth_alg) {
- case IW_AUTH_ALG_OPEN_SYSTEM:
- *auth_type = UMAC_AUTH_TYPE_OPEN;
- break;
- case IW_AUTH_ALG_SHARED_KEY:
- if (iwm->umac_profile->sec.flags &
- (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
- if (*auth_type == UMAC_AUTH_TYPE_8021X)
- return -EINVAL;
- *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
- } else {
- *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
- }
- break;
- case IW_AUTH_ALG_LEAP:
- default:
- IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- int ret;
-
- if ((data->flags) &
- (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
- IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
- /* We need to invalidate the current profile */
- if (iwm->umac_profile_active) {
- ret = iwm_invalidate_mlme_profile(iwm);
- if (ret < 0) {
- IWM_ERR(iwm, "Couldn't invalidate profile\n");
- return ret;
- }
- }
- }
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- return iwm_set_wpa_version(iwm, data->value);
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- return iwm_set_cipher(iwm, data->value, 1);
- break;
- case IW_AUTH_CIPHER_GROUP:
- return iwm_set_cipher(iwm, data->value, 0);
- break;
- case IW_AUTH_KEY_MGMT:
- return iwm_set_key_mgt(iwm, data->value);
- break;
- case IW_AUTH_80211_AUTH_ALG:
- return iwm_set_auth_alg(iwm, data->value);
- break;
- default:
- return -ENOTSUPP;
- }
-
- return 0;
-}
-
-static int iwm_wext_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_param *data, char *extra)
-{
- return 0;
-}
-
-static int iwm_wext_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *extra)
-{
- struct iwm_priv *iwm = ndev_to_iwm(dev);
- struct iwm_key *key;
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- int uninitialized_var(alg), idx, i, remove = 0;
-
- IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
- IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
- IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
- IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
- IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_NONE:
- remove = 1;
- break;
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len == WLAN_KEY_LEN_WEP40)
- alg = UMAC_CIPHER_TYPE_WEP_40;
- else if (ext->key_len == WLAN_KEY_LEN_WEP104)
- alg = UMAC_CIPHER_TYPE_WEP_104;
- else {
- IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
- return -EINVAL;
- }
-
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = UMAC_CIPHER_TYPE_TKIP;
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = UMAC_CIPHER_TYPE_CCMP;
- break;
+ case UMAC_MODE_BSS:
+ return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
default:
return -EOPNOTSUPP;
}
-
- idx = erq->flags & IW_ENCODE_INDEX;
-
- if (idx == 0) {
- if (iwm->default_key)
- for (i = 0; i < IWM_NUM_KEYS; i++) {
- if (iwm->default_key == &iwm->keys[i]) {
- idx = i;
- break;
- }
- }
- } else if (idx < 1 || idx > 4) {
- return -EINVAL;
- } else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if ((erq->length == 0) ||
- (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
- iwm->default_key = &iwm->keys[idx];
- if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
- return iwm_set_tx_key(iwm, idx);
- }
-
- key = iwm_key_init(iwm, idx, !remove, ext, alg);
-
- return iwm_set_key(iwm, remove, !iwm->default_key, key);
}
static const iw_handler iwm_handlers[] =
@@ -690,26 +154,26 @@ static const iw_handler iwm_handlers[] =
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* SIOCSIWRATE */
- (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
+ (iw_handler) cfg80211_wext_giwrate, /* SIOCGIWRATE */
(iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
(iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
(iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
(iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
- (iw_handler) NULL, /* SIOCSIWTXPOW */
- (iw_handler) NULL, /* SIOCGIWTXPOW */
+ (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
+ (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) NULL, /* SIOCSIWRETRY */
(iw_handler) NULL, /* SIOCGIWRETRY */
- (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */
- (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */
- (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
- (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
+ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
+ (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
+ (iw_handler) cfg80211_wext_siwpower, /* SIOCSIWPOWER */
+ (iw_handler) cfg80211_wext_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWGENIE */
+ (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
(iw_handler) NULL, /* SIOCGIWGENIE */
- (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
- (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
- (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */
+ (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
+ (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
+ (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
(iw_handler) NULL, /* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
(iw_handler) NULL, /* -- hole -- */
@@ -718,6 +182,6 @@ static const iw_handler iwm_handlers[] =
const struct iw_handler_def iwm_iw_handler_def = {
.num_standard = ARRAY_SIZE(iwm_handlers),
.standard = (iw_handler *) iwm_handlers,
- .get_wireless_stats = iwm_get_wireless_stats,
+ .get_wireless_stats = cfg80211_wireless_stats,
};
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index d6997371c27..1902b6f0b78 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -127,7 +127,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
{
struct cmd_ds_802_11_authenticate cmd;
int ret = -1;
- DECLARE_MAC_BUF(mac);
lbs_deb_enter(LBS_DEB_JOIN);
@@ -136,8 +135,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
cmd.authtype = iw_auth_to_ieee_auth(auth);
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bssid), cmd.authtype);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
@@ -340,8 +338,6 @@ static int lbs_associate(struct lbs_private *priv,
/* Firmware v9+ indicate authentication suites as a TLV */
if (priv->fwrelease >= 0x09000000) {
- DECLARE_MAC_BUF(mac);
-
auth = (struct mrvl_ie_auth_type *) pos;
auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
auth->header.len = cpu_to_le16(2);
@@ -349,8 +345,8 @@ static int lbs_associate(struct lbs_private *priv,
auth->auth = cpu_to_le16(tmpauth);
pos += sizeof(auth->header) + 2;
- lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
- print_mac(mac, bss->bssid), priv->secinfo.auth_mode);
+ lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
+ bss->bssid, priv->secinfo.auth_mode);
}
/* WPA/WPA2 IEs */
@@ -1366,11 +1362,17 @@ static int assoc_helper_wpa_keys(struct lbs_private *priv,
if (ret)
goto out;
+ memcpy(&priv->wpa_unicast_key, &assoc_req->wpa_unicast_key,
+ sizeof(struct enc_key));
+
if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
ret = lbs_cmd_802_11_key_material(priv, CMD_ACT_SET, assoc_req);
assoc_req->flags = flags;
+
+ memcpy(&priv->wpa_mcast_key, &assoc_req->wpa_mcast_key,
+ sizeof(struct enc_key));
}
out:
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index f9ec69e0473..578c6978358 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -260,7 +260,6 @@ struct lbs_private {
u16 psmode; /* Wlan802_11PowermodeCAM=disable
Wlan802_11PowermodeMAX_PSP=enable */
u32 psstate;
- char ps_supported;
u8 needtowakeup;
struct assoc_request * pending_assoc_req;
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 2a5b083bf9b..f658fd6a2c0 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -933,9 +933,6 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
goto out3;
}
- /* The firmware for the CF card supports powersave */
- priv->ps_supported = 1;
-
ret = 0;
goto out;
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 8cdb88c6ca2..485a8d40652 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -1039,9 +1039,6 @@ static int if_sdio_probe(struct sdio_func *func,
if (ret)
goto err_activate_card;
- if (priv->fwcapinfo & FW_CAPINFO_PS)
- priv->ps_supported = 1;
-
out:
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -1096,11 +1093,11 @@ static void if_sdio_remove(struct sdio_func *func)
lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
}
- card->priv->surpriseremoved = 1;
lbs_deb_sdio("call remove card\n");
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
+ card->priv->surpriseremoved = 1;
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 6564282ce47..963c20125fc 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -737,7 +737,7 @@ static int if_spi_c2h_data(struct if_spi_card *card)
goto out;
} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
lbs_pr_err("%s: error: card has %d bytes of data, but "
- "our maximum skb size is %lu\n",
+ "our maximum skb size is %zu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL;
goto out;
@@ -1118,7 +1118,6 @@ static int __devinit if_spi_probe(struct spi_device *spi)
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
priv->fw_ready = 1;
- priv->ps_supported = 1;
/* Initialize interrupt handling stuff. */
card->run_thread = 1;
@@ -1171,12 +1170,13 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
lbs_deb_spi("libertas_spi_remove\n");
lbs_deb_enter(LBS_DEB_SPI);
- priv->surpriseremoved = 1;
lbs_stop_card(priv);
+ lbs_remove_card(priv); /* will call free_netdev */
+
+ priv->surpriseremoved = 1;
free_irq(spi->irq, card);
if_spi_terminate_spi_thread(card);
- lbs_remove_card(priv); /* will call free_netdev */
if (card->pdata->teardown)
card->pdata->teardown(spi);
free_if_spi_card(card);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 1844c5adf6e..92bc8c5f1ca 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -181,13 +181,14 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
wake_method.action = cpu_to_le16(CMD_ACT_GET);
if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
lbs_pr_info("Firmware does not seem to support PS mode\n");
+ priv->fwcapinfo &= ~FW_CAPINFO_PS;
} else {
if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
lbs_deb_usb("Firmware seems to support PS with wake-via-command\n");
- priv->ps_supported = 1;
} else {
/* The versions which boot up this way don't seem to
work even if we set it to the command interrupt */
+ priv->fwcapinfo &= ~FW_CAPINFO_PS;
lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
}
}
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 8bc1907458b..e96451ce470 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -712,7 +712,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
lbs_deb_enter(LBS_DEB_WEXT);
- if (!priv->ps_supported) {
+ if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
if (vwrq->disabled)
return 0;
else
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 10a99e26d39..4872345a2f6 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -503,7 +503,8 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb)
skb_reserve(skb, 2);
}
- ieee80211_rx_irqsafe(priv->hw, skb, &stats);
+ memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+ ieee80211_rx_irqsafe(priv->hw, skb);
return 0;
}
EXPORT_SYMBOL_GPL(lbtf_rx);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 7916ca3f84c..930f5c7da4a 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -15,6 +15,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <net/dst.h>
+#include <net/xfrm.h>
#include <net/mac80211.h>
#include <net/ieee80211_radiotap.h>
#include <linux/if_arp.h>
@@ -314,7 +316,7 @@ static int hwsim_mon_xmit(struct sk_buff *skb, struct net_device *dev)
{
/* TODO: allow packet injection */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
@@ -404,11 +406,19 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
rx_status.freq = data->channel->center_freq;
rx_status.band = data->channel->band;
rx_status.rate_idx = info->control.rates[0].idx;
- /* TODO: simulate signal strength (and optional packet drop) */
+ /* TODO: simulate real signal strength (and optional packet loss) */
+ rx_status.signal = -50;
if (data->ps != PS_DISABLED)
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+ /* release the skb's source info */
+ skb_orphan(skb);
+ skb_dst_drop(skb);
+ skb->mark = 0;
+ secpath_reset(skb);
+ nf_reset(skb);
+
/* Copy skb to all enabled radios that are on the current frequency */
spin_lock(&hwsim_radio_lock);
list_for_each_entry(data2, &hwsim_radios, list) {
@@ -430,7 +440,8 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
if (memcmp(hdr->addr1, data2->hw->wiphy->perm_addr,
ETH_ALEN) == 0)
ack = true;
- ieee80211_rx_irqsafe(data2->hw, nskb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(data2->hw, nskb);
}
spin_unlock(&hwsim_radio_lock);
@@ -690,6 +701,74 @@ static int mac80211_hwsim_conf_tx(
return 0;
}
+#ifdef CONFIG_NL80211_TESTMODE
+/*
+ * This section contains example code for using netlink
+ * attributes with the testmode command in nl80211.
+ */
+
+/* These enums need to be kept in sync with userspace */
+enum hwsim_testmode_attr {
+ __HWSIM_TM_ATTR_INVALID = 0,
+ HWSIM_TM_ATTR_CMD = 1,
+ HWSIM_TM_ATTR_PS = 2,
+
+ /* keep last */
+ __HWSIM_TM_ATTR_AFTER_LAST,
+ HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1
+};
+
+enum hwsim_testmode_cmd {
+ HWSIM_TM_CMD_SET_PS = 0,
+ HWSIM_TM_CMD_GET_PS = 1,
+};
+
+static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = {
+ [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 },
+ [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 },
+};
+
+static int hwsim_fops_ps_write(void *dat, u64 val);
+
+static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
+ void *data, int len)
+{
+ struct mac80211_hwsim_data *hwsim = hw->priv;
+ struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1];
+ struct sk_buff *skb;
+ int err, ps;
+
+ err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len,
+ hwsim_testmode_policy);
+ if (err)
+ return err;
+
+ if (!tb[HWSIM_TM_ATTR_CMD])
+ return -EINVAL;
+
+ switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) {
+ case HWSIM_TM_CMD_SET_PS:
+ if (!tb[HWSIM_TM_ATTR_PS])
+ return -EINVAL;
+ ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]);
+ return hwsim_fops_ps_write(hwsim, ps);
+ case HWSIM_TM_CMD_GET_PS:
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ nla_total_size(sizeof(u32)));
+ if (!skb)
+ return -ENOMEM;
+ NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps);
+ return cfg80211_testmode_reply(skb);
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ nla_put_failure:
+ kfree_skb(skb);
+ return -ENOBUFS;
+}
+#endif
+
static const struct ieee80211_ops mac80211_hwsim_ops =
{
.tx = mac80211_hwsim_tx,
@@ -703,6 +782,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
.sta_notify = mac80211_hwsim_sta_notify,
.set_tim = mac80211_hwsim_set_tim,
.conf_tx = mac80211_hwsim_conf_tx,
+ CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
};
@@ -757,7 +837,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
{
struct mac80211_hwsim_data *data = dat;
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
- DECLARE_MAC_BUF(buf);
struct sk_buff *skb;
struct ieee80211_pspoll *pspoll;
@@ -787,7 +866,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
struct ieee80211_vif *vif, int ps)
{
struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
- DECLARE_MAC_BUF(buf);
struct sk_buff *skb;
struct ieee80211_hdr *hdr;
@@ -945,7 +1023,8 @@ static int __init init_mac80211_hwsim(void)
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT);
- hw->flags = IEEE80211_HW_MFP_CAPABLE;
+ hw->flags = IEEE80211_HW_MFP_CAPABLE |
+ IEEE80211_HW_SIGNAL_DBM;
/* ask mac80211 to reserve space for magic */
hw->vif_data_size = sizeof(struct hwsim_vif_priv);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index a263d5c84c0..4f725473fb7 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -1047,7 +1047,8 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
status.flag = 0;
status.band = IEEE80211_BAND_2GHZ;
status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
- ieee80211_rx_irqsafe(hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(hw, skb);
processed++;
}
@@ -2270,7 +2271,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
struct mwl8k_cmd_update_sta_db *cmd;
struct peer_capability_info *peer_info;
struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
- DECLARE_MAC_BUF(mac);
int rc;
__u8 count, *rates;
@@ -3479,7 +3479,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
{
struct ieee80211_hw *hw;
struct mwl8k_priv *priv;
- DECLARE_MAC_BUF(mac);
int rc;
int i;
u8 *fw;
@@ -3668,8 +3667,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
MWL8K_DESC);
printk(KERN_INFO "%s: Driver Ver:%s Firmware Ver:%u.%u.%u.%u\n",
priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
- printk(KERN_INFO "%s: MAC Address: %s\n", priv->name,
- print_mac(mac, hw->wiphy->perm_addr));
+ printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
+ hw->wiphy->perm_addr);
return 0;
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index d63c8992f22..712f26eef35 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -1047,7 +1047,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
} /* netwave_start_xmit */
/*
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 44411eb4e91..83b635fd778 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -1,6 +1,7 @@
config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA) && WLAN_80211
+ depends on CFG80211
select WIRELESS_EXT
select FW_LOADER
select CRYPTO
diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile
index 1fc7409d669..9abd6329bcb 100644
--- a/drivers/net/wireless/orinoco/Makefile
+++ b/drivers/net/wireless/orinoco/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the orinoco wireless device drivers.
#
-orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o
+orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o
obj-$(CONFIG_HERMES) += orinoco.o
obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index 8c4065f1b0d..c60df2c1aca 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -27,6 +27,7 @@
struct airport {
struct macio_dev *mdev;
void __iomem *vaddr;
+ unsigned int irq;
int irq_requested;
int ndev_registered;
};
@@ -34,8 +35,9 @@ struct airport {
static int
airport_suspend(struct macio_dev *mdev, pm_message_t state)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+ struct net_device *dev = priv->ndev;
+ struct airport *card = priv->card;
unsigned long flags;
int err;
@@ -48,18 +50,10 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
return 0;
}
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: PBOOK_SLEEP_NOW: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
+ orinoco_down(priv);
orinoco_unlock(priv, &flags);
- disable_irq(dev->irq);
+ disable_irq(card->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
macio_get_of_node(mdev), 0, 0);
@@ -69,8 +63,9 @@ airport_suspend(struct macio_dev *mdev, pm_message_t state)
static int
airport_resume(struct macio_dev *mdev)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
+ struct net_device *dev = priv->ndev;
+ struct airport *card = priv->card;
unsigned long flags;
int err;
@@ -80,47 +75,27 @@ airport_resume(struct macio_dev *mdev)
macio_get_of_node(mdev), 0, 1);
msleep(200);
- enable_irq(dev->irq);
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware on PBOOK_WAKE\n",
- dev->name, err);
- return 0;
- }
+ enable_irq(card->irq);
spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
-
- priv->hw_unavailable--;
-
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
- dev->name, err);
- }
-
-
+ err = orinoco_up(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
+ return err;
}
static int
airport_detach(struct macio_dev *mdev)
{
- struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
struct airport *card = priv->card;
if (card->ndev_registered)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
card->ndev_registered = 0;
if (card->irq_requested)
- free_irq(dev->irq, dev);
+ free_irq(card->irq, priv);
card->irq_requested = 0;
if (card->vaddr)
@@ -134,7 +109,7 @@ airport_detach(struct macio_dev *mdev)
ssleep(1);
macio_set_drvdata(mdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
return 0;
}
@@ -146,7 +121,6 @@ static int airport_hard_reset(struct orinoco_private *priv)
* re-initialize properly, it falls in a screaming heap
* shortly afterwards. */
#if 0
- struct net_device *dev = priv->ndev;
struct airport *card = priv->card;
/* Vitally important. If we don't do this it seems we get an
@@ -154,7 +128,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
* hw_unavailable is already set it doesn't get ACKed, we get
* into an interrupt loop and the PMU decides to turn us
* off. */
- disable_irq(dev->irq);
+ disable_irq(card->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
macio_get_of_node(card->mdev), 0, 0);
@@ -163,7 +137,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
macio_get_of_node(card->mdev), 0, 1);
ssleep(1);
- enable_irq(dev->irq);
+ enable_irq(card->irq);
ssleep(1);
#endif
@@ -174,7 +148,6 @@ static int
airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
struct orinoco_private *priv;
- struct net_device *dev;
struct airport *card;
unsigned long phys_addr;
hermes_t *hw;
@@ -185,33 +158,29 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
}
/* Allocate space for private device-specific data */
- dev = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
- airport_hard_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
+ airport_hard_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
return -ENODEV;
}
- priv = netdev_priv(dev);
card = priv->card;
hw = &priv->hw;
card->mdev = mdev;
- if (macio_request_resource(mdev, 0, "airport")) {
+ if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
printk(KERN_ERR PFX "can't request IO resource !\n");
- free_orinocodev(dev);
+ free_orinocodev(priv);
return -EBUSY;
}
- SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
-
- macio_set_drvdata(mdev, dev);
+ macio_set_drvdata(mdev, priv);
/* Setup interrupts & base address */
- dev->irq = macio_irq(mdev, 0);
+ card->irq = macio_irq(mdev, 0);
phys_addr = macio_resource_start(mdev, 0); /* Physical address */
printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
- dev->base_addr = phys_addr;
card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
if (!card->vaddr) {
printk(KERN_ERR PFX "ioremap() failed\n");
@@ -228,18 +197,23 @@ airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
/* Reset it before we get the interrupt */
hermes_init(hw);
- if (request_irq(dev->irq, orinoco_interrupt, 0, dev->name, dev)) {
- printk(KERN_ERR PFX "Couldn't get IRQ %d\n", dev->irq);
+ if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
+ printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
goto failed;
}
card->irq_requested = 1;
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, phys_addr, card->irq) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
- printk(KERN_DEBUG PFX "Card registered for interface %s\n", dev->name);
card->ndev_registered = 1;
return 0;
failed:
diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c
new file mode 100644
index 00000000000..1a87d3a0967
--- /dev/null
+++ b/drivers/net/wireless/orinoco/cfg.c
@@ -0,0 +1,162 @@
+/* cfg80211 support
+ *
+ * See copyright notice in main.c
+ */
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "hw.h"
+#include "main.h"
+#include "orinoco.h"
+
+#include "cfg.h"
+
+/* Supported bitrates. Must agree with hw.c */
+static struct ieee80211_rate orinoco_rates[] = {
+ { .bitrate = 10 },
+ { .bitrate = 20 },
+ { .bitrate = 55 },
+ { .bitrate = 110 },
+};
+
+static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
+
+/* Called after orinoco_private is allocated. */
+void orinoco_wiphy_init(struct wiphy *wiphy)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+
+ wiphy->privid = orinoco_wiphy_privid;
+
+ set_wiphy_dev(wiphy, priv->dev);
+}
+
+/* Called after firmware is initialised */
+int orinoco_wiphy_register(struct wiphy *wiphy)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int i, channels = 0;
+
+ if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+ wiphy->max_scan_ssids = 1;
+ else
+ wiphy->max_scan_ssids = 0;
+
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ /* TODO: should we set if we only have demo ad-hoc?
+ * (priv->has_port3)
+ */
+ if (priv->has_ibss)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+
+ if (!priv->broken_monitor || force_monitor)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+
+ priv->band.bitrates = orinoco_rates;
+ priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
+
+ /* Only support channels allowed by the card EEPROM */
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (priv->channel_mask & (1 << i)) {
+ priv->channels[i].center_freq =
+ ieee80211_dsss_chan_to_freq(i+1);
+ channels++;
+ }
+ }
+ priv->band.channels = priv->channels;
+ priv->band.n_channels = channels;
+
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ i = 0;
+ if (priv->has_wep) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
+ i++;
+
+ if (priv->has_big_wep) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
+ i++;
+ }
+ }
+ if (priv->has_wpa) {
+ priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
+ i++;
+ }
+ wiphy->cipher_suites = priv->cipher_suites;
+ wiphy->n_cipher_suites = i;
+
+ wiphy->rts_threshold = priv->rts_thresh;
+ if (!priv->has_mwo)
+ wiphy->frag_threshold = priv->frag_thresh;
+
+ return wiphy_register(wiphy);
+}
+
+static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err = 0;
+ unsigned long lock;
+
+ if (orinoco_lock(priv, &lock) != 0)
+ return -EBUSY;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ if (!priv->has_ibss && !priv->has_port3)
+ err = -EINVAL;
+ break;
+
+ case NL80211_IFTYPE_STATION:
+ break;
+
+ case NL80211_IFTYPE_MONITOR:
+ if (priv->broken_monitor && !force_monitor) {
+ printk(KERN_WARNING "%s: Monitor mode support is "
+ "buggy in this firmware, not enabling\n",
+ wiphy_name(wiphy));
+ err = -EINVAL;
+ }
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ if (!err) {
+ priv->iw_mode = type;
+ set_port_type(priv);
+ err = orinoco_commit(priv);
+ }
+
+ orinoco_unlock(priv, &lock);
+
+ return err;
+}
+
+static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ struct orinoco_private *priv = wiphy_priv(wiphy);
+ int err;
+
+ if (!request)
+ return -EINVAL;
+
+ if (priv->scan_request && priv->scan_request != request)
+ return -EBUSY;
+
+ priv->scan_request = request;
+
+ err = orinoco_hw_trigger_scan(priv, request->ssids);
+
+ return err;
+}
+
+const struct cfg80211_ops orinoco_cfg_ops = {
+ .change_virtual_intf = orinoco_change_vif,
+ .scan = orinoco_scan,
+};
diff --git a/drivers/net/wireless/orinoco/cfg.h b/drivers/net/wireless/orinoco/cfg.h
new file mode 100644
index 00000000000..3ddc96a06cd
--- /dev/null
+++ b/drivers/net/wireless/orinoco/cfg.h
@@ -0,0 +1,15 @@
+/* cfg80211 support.
+ *
+ * See copyright notice in main.c
+ */
+#ifndef ORINOCO_CFG_H
+#define ORINOCO_CFG_H
+
+#include <net/cfg80211.h>
+
+extern const struct cfg80211_ops orinoco_cfg_ops;
+
+void orinoco_wiphy_init(struct wiphy *wiphy);
+int orinoco_wiphy_register(struct wiphy *wiphy);
+
+#endif /* ORINOCO_CFG_H */
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 1084b43e04b..1257250a1e2 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -4,6 +4,7 @@
*/
#include <linux/kernel.h>
#include <linux/firmware.h>
+#include <linux/device.h>
#include "hermes.h"
#include "hermes_dld.h"
@@ -99,7 +100,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
const void *end;
const char *firmware;
const char *fw_err;
- struct net_device *dev = priv->ndev;
+ struct device *dev = priv->dev;
int err = 0;
pda = kzalloc(fw->pda_size, GFP_KERNEL);
@@ -111,12 +112,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
else
firmware = fw->sta_fw;
- printk(KERN_DEBUG "%s: Attempting to download firmware %s\n",
- dev->name, firmware);
+ dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
/* Read current plug data */
err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
- printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
+ dev_dbg(dev, "Read PDA returned %d\n", err);
if (err)
goto free;
@@ -124,8 +124,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
err = request_firmware(&fw_entry, firmware, priv->dev);
if (err) {
- printk(KERN_ERR "%s: Cannot find firmware %s\n",
- dev->name, firmware);
+ dev_err(dev, "Cannot find firmware %s\n", firmware);
err = -ENOENT;
goto free;
}
@@ -136,16 +135,15 @@ orinoco_dl_firmware(struct orinoco_private *priv,
fw_err = validate_fw(hdr, fw_entry->size);
if (fw_err) {
- printk(KERN_WARNING "%s: Invalid firmware image detected (%s). "
- "Aborting download\n",
- dev->name, fw_err);
+ dev_warn(dev, "Invalid firmware image detected (%s). "
+ "Aborting download\n", fw_err);
err = -EINVAL;
goto abort;
}
/* Enable aux port to allow programming */
err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
- printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program init returned %d\n", err);
if (err != 0)
goto abort;
@@ -156,7 +154,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
end = fw_entry->data + fw_entry->size;
err = hermes_program(hw, first_block, end);
- printk(KERN_DEBUG "%s: Program returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program returned %d\n", err);
if (err != 0)
goto abort;
@@ -167,19 +165,18 @@ orinoco_dl_firmware(struct orinoco_private *priv,
err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
&pda[fw->pda_size / sizeof(*pda)]);
- printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
+ dev_dbg(dev, "Apply PDA returned %d\n", err);
if (err)
goto abort;
/* Tell card we've finished */
err = hermesi_program_end(hw);
- printk(KERN_DEBUG "%s: Program end returned %d\n", dev->name, err);
+ dev_dbg(dev, "Program end returned %d\n", err);
if (err != 0)
goto abort;
/* Check if we're running */
- printk(KERN_DEBUG "%s: hermes_present returned %d\n",
- dev->name, hermes_present(hw));
+ dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw));
abort:
/* If we requested the firmware, release it. */
@@ -282,14 +279,13 @@ static int
symbol_dl_firmware(struct orinoco_private *priv,
const struct fw_info *fw)
{
- struct net_device *dev = priv->ndev;
+ struct device *dev = priv->dev;
int ret;
const struct firmware *fw_entry;
if (!orinoco_cached_fw_get(priv, true)) {
if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->pri_fw);
+ dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw);
return -ENOENT;
}
} else
@@ -302,15 +298,13 @@ symbol_dl_firmware(struct orinoco_private *priv,
if (!orinoco_cached_fw_get(priv, true))
release_firmware(fw_entry);
if (ret) {
- printk(KERN_ERR "%s: Primary firmware download failed\n",
- dev->name);
+ dev_err(dev, "Primary firmware download failed\n");
return ret;
}
if (!orinoco_cached_fw_get(priv, false)) {
if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
- printk(KERN_ERR "%s: Cannot find firmware: %s\n",
- dev->name, fw->sta_fw);
+ dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw);
return -ENOENT;
}
} else
@@ -322,8 +316,7 @@ symbol_dl_firmware(struct orinoco_private *priv,
if (!orinoco_cached_fw_get(priv, false))
release_firmware(fw_entry);
if (ret) {
- printk(KERN_ERR "%s: Secondary firmware download failed\n",
- dev->name);
+ dev_err(dev, "Secondary firmware download failed\n");
}
return ret;
diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c
index f2c918c2572..1a2fca76fd3 100644
--- a/drivers/net/wireless/orinoco/hermes.c
+++ b/drivers/net/wireless/orinoco/hermes.c
@@ -469,7 +469,7 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
u16 rlength, rtype;
unsigned nwords;
- if ((bufsize < 0) || (bufsize % 2))
+ if (bufsize % 2)
return -EINVAL;
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index c78c442a02c..2dddbb597c4 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -342,7 +342,7 @@ struct agere_ext_scan_info {
__le64 timestamp;
__le16 beacon_interval;
__le16 capabilities;
- u8 data[316];
+ u8 data[0];
} __attribute__ ((packed));
#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index a9ba195cdad..a3eefe109df 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -309,7 +309,7 @@ int hermes_read_pda(hermes_t *hw,
/* Open auxiliary port */
ret = hermes_aux_control(hw, 1);
- printk(KERN_DEBUG PFX "AUX enable returned %d\n", ret);
+ pr_debug(PFX "AUX enable returned %d\n", ret);
if (ret)
return ret;
@@ -319,12 +319,12 @@ int hermes_read_pda(hermes_t *hw,
/* Close aux port */
ret = hermes_aux_control(hw, 0);
- printk(KERN_DEBUG PFX "AUX disable returned %d\n", ret);
+ pr_debug(PFX "AUX disable returned %d\n", ret);
/* Check PDA length */
pda_size = le16_to_cpu(pda[0]);
- printk(KERN_DEBUG PFX "Actual PDA length %d, Max allowed %d\n",
- pda_size, pda_len);
+ pr_debug(PFX "Actual PDA length %d, Max allowed %d\n",
+ pda_size, pda_len);
if (pda_size > pda_len)
return -EINVAL;
@@ -422,20 +422,19 @@ int hermesi_program_init(hermes_t *hw, u32 offset)
return err;
err = hermes_aux_control(hw, 1);
- printk(KERN_DEBUG PFX "AUX enable returned %d\n", err);
+ pr_debug(PFX "AUX enable returned %d\n", err);
if (err)
return err;
- printk(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
+ pr_debug(KERN_DEBUG PFX "Enabling volatile, EP 0x%08x\n", offset);
err = hermes_doicmd_wait(hw,
HERMES_PROGRAM_ENABLE_VOLATILE,
offset & 0xFFFFu,
offset >> 16,
0,
NULL);
- printk(KERN_DEBUG PFX "PROGRAM_ENABLE returned %d\n",
- err);
+ pr_debug(PFX "PROGRAM_ENABLE returned %d\n", err);
return err;
}
@@ -454,16 +453,16 @@ int hermesi_program_end(hermes_t *hw)
rc = hermes_docmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
- printk(KERN_DEBUG PFX "PROGRAM_DISABLE returned %d, "
- "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
- rc, resp.resp0, resp.resp1, resp.resp2);
+ pr_debug(PFX "PROGRAM_DISABLE returned %d, "
+ "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
+ rc, resp.resp0, resp.resp1, resp.resp2);
if ((rc == 0) &&
((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
rc = -EIO;
err = hermes_aux_control(hw, 0);
- printk(KERN_DEBUG PFX "AUX disable returned %d\n", err);
+ pr_debug(PFX "AUX disable returned %d\n", err);
/* Acknowledge any outstanding command */
hermes_write_regn(hw, EVACK, 0xFFFF);
@@ -496,9 +495,8 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
while ((blkaddr != BLOCK_END) &&
(((void *) blk + blklen) <= end)) {
- printk(KERN_DEBUG PFX
- "Programming block of length %d to address 0x%08x\n",
- blklen, blkaddr);
+ pr_debug(PFX "Programming block of length %d "
+ "to address 0x%08x\n", blklen, blkaddr);
#if !LIMIT_PROGRAM_SIZE
/* wl_lkm driver splits this into writes of 2000 bytes */
@@ -510,10 +508,9 @@ int hermes_program(hermes_t *hw, const char *first_block, const void *end)
addr = blkaddr;
while (addr < (blkaddr + blklen)) {
- printk(KERN_DEBUG PFX
- "Programming subblock of length %d "
- "to address 0x%08x. Data @ %p\n",
- len, addr, &blk->data[addr - blkaddr]);
+ pr_debug(PFX "Programming subblock of length %d "
+ "to address 0x%08x. Data @ %p\n",
+ len, addr, &blk->data[addr - blkaddr]);
hermes_aux_setaddr(hw, addr);
hermes_write_bytes(hw, HERMES_AUXDATA,
@@ -643,8 +640,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
if (pdi)
- printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
- record_id, pdi);
+ pr_debug(PFX "Found record 0x%04x at %p\n",
+ record_id, pdi);
switch (record_id) {
case 0x110: /* Modem REFDAC values */
@@ -654,9 +651,9 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
default_pdi = NULL;
if (outdoor_pdi) {
pdi = outdoor_pdi;
- printk(KERN_DEBUG PFX
- "Using outdoor record 0x%04x at %p\n",
- record_id + 1, pdi);
+ pr_debug(PFX
+ "Using outdoor record 0x%04x at %p\n",
+ record_id + 1, pdi);
}
break;
case 0x5: /* HWIF Compatiblity */
@@ -684,9 +681,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
if (!pdi && default_pdi) {
/* Use default */
pdi = default_pdi;
- printk(KERN_DEBUG PFX
- "Using default record 0x%04x at %p\n",
- record_id, pdi);
+ pr_debug(PFX "Using default record 0x%04x at %p\n",
+ record_id, pdi);
}
if (pdi) {
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 632fac86a30..fa508af1a35 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -3,16 +3,22 @@
* See copyright notice in main.c
*/
#include <linux/kernel.h>
+#include <linux/device.h>
#include <linux/if_arp.h>
#include <linux/ieee80211.h>
#include <linux/wireless.h>
-
+#include <net/cfg80211.h>
#include "hermes.h"
#include "hermes_rid.h"
#include "orinoco.h"
#include "hw.h"
+#define SYMBOL_MAX_VER_LEN (14)
+
+/* Symbol firmware has a bug allocating buffers larger than this */
+#define TX_NICBUF_SIZE_BUG 1585
+
/********************************************************************/
/* Data tables */
/********************************************************************/
@@ -36,6 +42,343 @@ static const struct {
};
#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
+/* Firmware version encoding */
+struct comp_id {
+ u16 id, variant, major, minor;
+} __attribute__ ((packed));
+
+static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
+{
+ if (nic_id->id < 0x8000)
+ return FIRMWARE_TYPE_AGERE;
+ else if (nic_id->id == 0x8000 && nic_id->major == 0)
+ return FIRMWARE_TYPE_SYMBOL;
+ else
+ return FIRMWARE_TYPE_INTERSIL;
+}
+
+/* Set priv->firmware type, determine firmware properties
+ * This function can be called before we have registerred with netdev,
+ * so all errors go out with dev_* rather than printk
+ */
+int determine_fw_capabilities(struct orinoco_private *priv)
+{
+ struct device *dev = priv->dev;
+ hermes_t *hw = &priv->hw;
+ int err;
+ struct comp_id nic_id, sta_id;
+ unsigned int firmver;
+ char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
+
+ /* Get the hardware version */
+ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
+ if (err) {
+ dev_err(dev, "Cannot read hardware identity: error %d\n",
+ err);
+ return err;
+ }
+
+ le16_to_cpus(&nic_id.id);
+ le16_to_cpus(&nic_id.variant);
+ le16_to_cpus(&nic_id.major);
+ le16_to_cpus(&nic_id.minor);
+ dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
+ nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
+
+ priv->firmware_type = determine_firmware_type(&nic_id);
+
+ /* Get the firmware version */
+ err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
+ if (err) {
+ dev_err(dev, "Cannot read station identity: error %d\n",
+ err);
+ return err;
+ }
+
+ le16_to_cpus(&sta_id.id);
+ le16_to_cpus(&sta_id.variant);
+ le16_to_cpus(&sta_id.major);
+ le16_to_cpus(&sta_id.minor);
+ dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n",
+ sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
+
+ switch (sta_id.id) {
+ case 0x15:
+ dev_err(dev, "Primary firmware is active\n");
+ return -ENODEV;
+ case 0x14b:
+ dev_err(dev, "Tertiary firmware is active\n");
+ return -ENODEV;
+ case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
+ case 0x21: /* Symbol Spectrum24 Trilogy */
+ break;
+ default:
+ dev_notice(dev, "Unknown station ID, please report\n");
+ break;
+ }
+
+ /* Default capabilities */
+ priv->has_sensitivity = 1;
+ priv->has_mwo = 0;
+ priv->has_preamble = 0;
+ priv->has_port3 = 1;
+ priv->has_ibss = 1;
+ priv->has_wep = 0;
+ priv->has_big_wep = 0;
+ priv->has_alt_txcntl = 0;
+ priv->has_ext_scan = 0;
+ priv->has_wpa = 0;
+ priv->do_fw_download = 0;
+
+ /* Determine capabilities from the firmware version */
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_AGERE:
+ /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
+ ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
+
+ firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
+
+ priv->has_ibss = (firmver >= 0x60006);
+ priv->has_wep = (firmver >= 0x40020);
+ priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
+ Gold cards from the others? */
+ priv->has_mwo = (firmver >= 0x60000);
+ priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
+ priv->ibss_port = 1;
+ priv->has_hostscan = (firmver >= 0x8000a);
+ priv->do_fw_download = 1;
+ priv->broken_monitor = (firmver >= 0x80000);
+ priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
+ priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
+ priv->has_wpa = (firmver >= 0x9002a);
+ /* Tested with Agere firmware :
+ * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
+ * Tested CableTron firmware : 4.32 => Anton */
+ break;
+ case FIRMWARE_TYPE_SYMBOL:
+ /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
+ /* Intel MAC : 00:02:B3:* */
+ /* 3Com MAC : 00:50:DA:* */
+ memset(tmp, 0, sizeof(tmp));
+ /* Get the Symbol firmware version */
+ err = hermes_read_ltv(hw, USER_BAP,
+ HERMES_RID_SECONDARYVERSION_SYMBOL,
+ SYMBOL_MAX_VER_LEN, NULL, &tmp);
+ if (err) {
+ dev_warn(dev, "Error %d reading Symbol firmware info. "
+ "Wildly guessing capabilities...\n", err);
+ firmver = 0;
+ tmp[0] = '\0';
+ } else {
+ /* The firmware revision is a string, the format is
+ * something like : "V2.20-01".
+ * Quick and dirty parsing... - Jean II
+ */
+ firmver = ((tmp[1] - '0') << 16)
+ | ((tmp[3] - '0') << 12)
+ | ((tmp[4] - '0') << 8)
+ | ((tmp[6] - '0') << 4)
+ | (tmp[7] - '0');
+
+ tmp[SYMBOL_MAX_VER_LEN] = '\0';
+ }
+
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Symbol %s", tmp);
+
+ priv->has_ibss = (firmver >= 0x20000);
+ priv->has_wep = (firmver >= 0x15012);
+ priv->has_big_wep = (firmver >= 0x20000);
+ priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
+ (firmver >= 0x29000 && firmver < 0x30000) ||
+ firmver >= 0x31000;
+ priv->has_preamble = (firmver >= 0x20000);
+ priv->ibss_port = 4;
+
+ /* Symbol firmware is found on various cards, but
+ * there has been no attempt to check firmware
+ * download on non-spectrum_cs based cards.
+ *
+ * Given that the Agere firmware download works
+ * differently, we should avoid doing a firmware
+ * download with the Symbol algorithm on non-spectrum
+ * cards.
+ *
+ * For now we can identify a spectrum_cs based card
+ * because it has a firmware reset function.
+ */
+ priv->do_fw_download = (priv->stop_fw != NULL);
+
+ priv->broken_disableport = (firmver == 0x25013) ||
+ (firmver >= 0x30000 && firmver <= 0x31000);
+ priv->has_hostscan = (firmver >= 0x31001) ||
+ (firmver >= 0x29057 && firmver < 0x30000);
+ /* Tested with Intel firmware : 0x20015 => Jean II */
+ /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
+ break;
+ case FIRMWARE_TYPE_INTERSIL:
+ /* D-Link, Linksys, Adtron, ZoomAir, and many others...
+ * Samsung, Compaq 100/200 and Proxim are slightly
+ * different and less well tested */
+ /* D-Link MAC : 00:40:05:* */
+ /* Addtron MAC : 00:90:D1:* */
+ snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
+ "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
+ sta_id.variant);
+
+ firmver = ((unsigned long)sta_id.major << 16) |
+ ((unsigned long)sta_id.minor << 8) | sta_id.variant;
+
+ priv->has_ibss = (firmver >= 0x000700); /* FIXME */
+ priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
+ priv->has_pm = (firmver >= 0x000700);
+ priv->has_hostscan = (firmver >= 0x010301);
+
+ if (firmver >= 0x000800)
+ priv->ibss_port = 0;
+ else {
+ dev_notice(dev, "Intersil firmware earlier than v0.8.x"
+ " - several features not supported\n");
+ priv->ibss_port = 1;
+ }
+ break;
+ }
+ dev_info(dev, "Firmware determined as %s\n", priv->fw_name);
+
+ return 0;
+}
+
+/* Read settings from EEPROM into our private structure.
+ * MAC address gets dropped into callers buffer
+ * Can be called before netdev registration.
+ */
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
+{
+ struct device *dev = priv->dev;
+ struct hermes_idstring nickbuf;
+ hermes_t *hw = &priv->hw;
+ int len;
+ int err;
+ u16 reclen;
+
+ /* Get the MAC address */
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+ ETH_ALEN, NULL, dev_addr);
+ if (err) {
+ dev_warn(dev, "Failed to read MAC address!\n");
+ goto out;
+ }
+
+ dev_dbg(dev, "MAC address %pM\n", dev_addr);
+
+ /* Get the station name */
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+ sizeof(nickbuf), &reclen, &nickbuf);
+ if (err) {
+ dev_err(dev, "failed to read station name\n");
+ goto out;
+ }
+ if (nickbuf.len)
+ len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
+ else
+ len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
+ memcpy(priv->nick, &nickbuf.val, len);
+ priv->nick[len] = '\0';
+
+ dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
+
+ /* Get allowed channels */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
+ &priv->channel_mask);
+ if (err) {
+ dev_err(dev, "Failed to read channel list!\n");
+ goto out;
+ }
+
+ /* Get initial AP density */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
+ &priv->ap_density);
+ if (err || priv->ap_density < 1 || priv->ap_density > 3)
+ priv->has_sensitivity = 0;
+
+ /* Get initial RTS threshold */
+ err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+ &priv->rts_thresh);
+ if (err) {
+ dev_err(dev, "Failed to read RTS threshold!\n");
+ goto out;
+ }
+
+ /* Get initial fragmentation settings */
+ if (priv->has_mwo)
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMWOROBUST_AGERE,
+ &priv->mwo_robust);
+ else
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+ &priv->frag_thresh);
+ if (err) {
+ dev_err(dev, "Failed to read fragmentation settings!\n");
+ goto out;
+ }
+
+ /* Power management setup */
+ if (priv->has_pm) {
+ priv->pm_on = 0;
+ priv->pm_mcast = 1;
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMAXSLEEPDURATION,
+ &priv->pm_period);
+ if (err) {
+ dev_err(dev, "Failed to read power management "
+ "period!\n");
+ goto out;
+ }
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMHOLDOVERDURATION,
+ &priv->pm_timeout);
+ if (err) {
+ dev_err(dev, "Failed to read power management "
+ "timeout!\n");
+ goto out;
+ }
+ }
+
+ /* Preamble setup */
+ if (priv->has_preamble) {
+ err = hermes_read_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPREAMBLE_SYMBOL,
+ &priv->preamble);
+ }
+
+out:
+ return err;
+}
+
+/* Can be called before netdev registration */
+int orinoco_hw_allocate_fid(struct orinoco_private *priv)
+{
+ struct device *dev = priv->dev;
+ struct hermes *hw = &priv->hw;
+ int err;
+
+ err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+ if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
+ /* Try workaround for old Symbol firmware bug */
+ priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
+ err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
+
+ dev_warn(dev, "Firmware ALLOC bug detected "
+ "(old Symbol firmware?). Work around %s\n",
+ err ? "failed!" : "ok.");
+ }
+
+ return err;
+}
+
int orinoco_get_bitratemode(int bitrate, int automatic)
{
int ratemode = -1;
@@ -63,6 +406,237 @@ void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
*automatic = bitrate_table[ratemode].automatic;
}
+int orinoco_hw_program_rids(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ struct wireless_dev *wdev = netdev_priv(dev);
+ hermes_t *hw = &priv->hw;
+ int err;
+ struct hermes_idstring idbuf;
+
+ /* Set the MAC address */
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
+ HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting MAC address\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set up the link mode */
+ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
+ priv->port_type);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting port type\n",
+ dev->name, err);
+ return err;
+ }
+ /* Set the channel/frequency */
+ if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFOWNCHANNEL,
+ priv->channel);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting channel %d\n",
+ dev->name, err, priv->channel);
+ return err;
+ }
+ }
+
+ if (priv->has_ibss) {
+ u16 createibss;
+
+ if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
+ printk(KERN_WARNING "%s: This firmware requires an "
+ "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
+ /* With wvlan_cs, in this case, we would crash.
+ * hopefully, this driver will behave better...
+ * Jean II */
+ createibss = 0;
+ } else {
+ createibss = priv->createibss;
+ }
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFCREATEIBSS,
+ createibss);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set the desired BSSID */
+ err = __orinoco_hw_set_wap(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting AP address\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set the desired ESSID */
+ idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
+ memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
+ /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set the station name */
+ idbuf.len = cpu_to_le16(strlen(priv->nick));
+ memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
+ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
+ HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
+ &idbuf);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting nickname\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set AP density */
+ if (priv->has_sensitivity) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSYSTEMSCALE,
+ priv->ap_density);
+ if (err) {
+ printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
+ "Disabling sensitivity control\n",
+ dev->name, err);
+
+ priv->has_sensitivity = 0;
+ }
+ }
+
+ /* Set RTS threshold */
+ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
+ priv->rts_thresh);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set fragmentation threshold or MWO robustness */
+ if (priv->has_mwo)
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMWOROBUST_AGERE,
+ priv->mwo_robust);
+ else
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
+ priv->frag_thresh);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting fragmentation\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set bitrate */
+ err = __orinoco_hw_set_bitrate(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting bitrate\n",
+ dev->name, err);
+ return err;
+ }
+
+ /* Set power management */
+ if (priv->has_pm) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMENABLED,
+ priv->pm_on);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMULTICASTRECEIVE,
+ priv->pm_mcast);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFMAXSLEEPDURATION,
+ priv->pm_period);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPMHOLDOVERDURATION,
+ priv->pm_timeout);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting up PM\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set preamble - only for Symbol so far... */
+ if (priv->has_preamble) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFPREAMBLE_SYMBOL,
+ priv->preamble);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting preamble\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ /* Set up encryption */
+ if (priv->has_wep || priv->has_wpa) {
+ err = __orinoco_hw_setup_enc(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d activating encryption\n",
+ dev->name, err);
+ return err;
+ }
+ }
+
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ /* Enable monitor mode */
+ dev->type = ARPHRD_IEEE80211;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_MONITOR, 0, NULL);
+ } else {
+ /* Disable monitor mode */
+ dev->type = ARPHRD_ETHER;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_STOP, 0, NULL);
+ }
+ if (err)
+ return err;
+
+ /* Reset promiscuity / multicast*/
+ priv->promiscuous = 0;
+ priv->mc_count = 0;
+
+ /* Record mode change */
+ wdev->iftype = priv->iw_mode;
+
+ return 0;
+}
+
/* Get tsc from the firmware */
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
{
@@ -314,7 +888,7 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
} else
master_wep_flag = 0;
- if (priv->iw_mode == IW_MODE_MONITOR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
/* Master WEP setting : on/off */
@@ -334,8 +908,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
* rsc must be 8 bytes
* tsc must be 8 bytes or NULL
*/
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
- u8 *key, u8 *rsc, u8 *tsc)
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+ int set_tx, u8 *key, u8 *rsc, u8 *tsc)
{
struct {
__le16 idx;
@@ -345,6 +919,7 @@ int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
u8 rx_mic[MIC_KEYLEN];
u8 tsc[IW_ENCODE_SEQ_MAX_SIZE];
} __attribute__ ((packed)) buf;
+ hermes_t *hw = &priv->hw;
int ret;
int err;
int k;
@@ -582,3 +1157,88 @@ int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
return 0;
}
+
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+ const struct cfg80211_ssid *ssid)
+{
+ struct net_device *dev = priv->ndev;
+ hermes_t *hw = &priv->hw;
+ unsigned long flags;
+ int err = 0;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ /* Scanning with port 0 disabled would fail */
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
+
+ /* In monitor mode, the scan results are always empty.
+ * Probe responses are passed to the driver as received
+ * frames and could be processed in software. */
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (priv->has_hostscan) {
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN_SYMBOL,
+ HERMES_HOSTSCAN_SYMBOL_ONCE |
+ HERMES_HOSTSCAN_SYMBOL_BCAST);
+ break;
+ case FIRMWARE_TYPE_INTERSIL: {
+ __le16 req[3];
+
+ req[0] = cpu_to_le16(0x3fff); /* All channels */
+ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
+ req[2] = 0; /* Any ESSID */
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN, &req);
+ break;
+ }
+ case FIRMWARE_TYPE_AGERE:
+ if (ssid->ssid_len > 0) {
+ struct hermes_idstring idbuf;
+ size_t len = ssid->ssid_len;
+
+ idbuf.len = cpu_to_le16(len);
+ memcpy(idbuf.val, ssid->ssid, len);
+
+ err = hermes_write_ltv(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ HERMES_BYTES_TO_RECLEN(len + 2),
+ &idbuf);
+ } else
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ 0); /* Any ESSID */
+ if (err)
+ break;
+
+ if (priv->has_ext_scan) {
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANCHANNELS2GHZ,
+ 0x7FFF);
+ if (err)
+ goto out;
+
+ err = hermes_inquire(hw,
+ HERMES_INQ_CHANNELINFO);
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ break;
+ }
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
+
+ out:
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
diff --git a/drivers/net/wireless/orinoco/hw.h b/drivers/net/wireless/orinoco/hw.h
index dc3f23a9c1c..27b427649d1 100644
--- a/drivers/net/wireless/orinoco/hw.h
+++ b/drivers/net/wireless/orinoco/hw.h
@@ -7,6 +7,7 @@
#include <linux/types.h>
#include <linux/wireless.h>
+#include <net/cfg80211.h>
/* Hardware BAPs */
#define USER_BAP 0
@@ -23,17 +24,21 @@
struct orinoco_private;
struct dev_addr_list;
+int determine_fw_capabilities(struct orinoco_private *priv);
+int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
+int orinoco_hw_allocate_fid(struct orinoco_private *priv);
int orinoco_get_bitratemode(int bitrate, int automatic);
void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
+int orinoco_hw_program_rids(struct orinoco_private *priv);
int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
int __orinoco_hw_set_wap(struct orinoco_private *priv);
int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
int __orinoco_hw_setup_enc(struct orinoco_private *priv);
-int __orinoco_hw_set_tkip_key(hermes_t *hw, int key_idx, int set_tx,
- u8 *key, u8 *rsc, u8 *tsc);
+int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
+ int set_tx, u8 *key, u8 *rsc, u8 *tsc);
int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
struct dev_addr_list *mc_list,
@@ -43,5 +48,7 @@ int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
int orinoco_hw_get_freq(struct orinoco_private *priv);
int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
int *numrates, s32 *rates, int max);
+int orinoco_hw_trigger_scan(struct orinoco_private *priv,
+ const struct cfg80211_ssid *ssid);
#endif /* _ORINOCO_HW_H_ */
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index a370e510f19..e8c550a61f3 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -80,6 +80,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
@@ -88,6 +89,7 @@
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes_rid.h"
#include "hermes_dld.h"
@@ -96,6 +98,7 @@
#include "mic.h"
#include "fw.h"
#include "wext.h"
+#include "cfg.h"
#include "main.h"
#include "orinoco.h"
@@ -142,13 +145,11 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define ORINOCO_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
-#define SYMBOL_MAX_VER_LEN (14)
#define MAX_IRQLOOPS_PER_IRQ 10
#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of
* how many events the
* device could
* legitimately generate */
-#define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */
#define DUMMY_FID 0xFFFF
@@ -205,11 +206,21 @@ struct orinoco_rx_data {
struct list_head list;
};
+struct orinoco_scan_data {
+ void *buf;
+ size_t len;
+ int type;
+ struct list_head list;
+};
+
/********************************************************************/
/* Function prototypes */
/********************************************************************/
-static void __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_set_multicast_list(struct net_device *dev);
+static int __orinoco_up(struct orinoco_private *priv);
+static int __orinoco_down(struct orinoco_private *priv);
+static int __orinoco_commit(struct orinoco_private *priv);
/********************************************************************/
/* Internal helper functions */
@@ -218,11 +229,11 @@ static void __orinoco_set_multicast_list(struct net_device *dev);
void set_port_type(struct orinoco_private *priv)
{
switch (priv->iw_mode) {
- case IW_MODE_INFRA:
+ case NL80211_IFTYPE_STATION:
priv->port_type = 1;
priv->createibss = 0;
break;
- case IW_MODE_ADHOC:
+ case NL80211_IFTYPE_ADHOC:
if (priv->prefer_port3) {
priv->port_type = 3;
priv->createibss = 0;
@@ -231,7 +242,7 @@ void set_port_type(struct orinoco_private *priv)
priv->createibss = 1;
}
break;
- case IW_MODE_MONITOR:
+ case NL80211_IFTYPE_MONITOR:
priv->port_type = 3;
priv->createibss = 0;
break;
@@ -247,14 +258,14 @@ void set_port_type(struct orinoco_private *priv)
static int orinoco_open(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- err = __orinoco_up(dev);
+ err = __orinoco_up(priv);
if (!err)
priv->open = 1;
@@ -266,7 +277,7 @@ static int orinoco_open(struct net_device *dev)
static int orinoco_stop(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
/* We mustn't use orinoco_lock() here, because we need to be
@@ -276,7 +287,7 @@ static int orinoco_stop(struct net_device *dev)
priv->open = 0;
- err = __orinoco_down(dev);
+ err = __orinoco_down(priv);
spin_unlock_irq(&priv->lock);
@@ -285,14 +296,14 @@ static int orinoco_stop(struct net_device *dev)
static struct net_device_stats *orinoco_get_stats(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
return &priv->stats;
}
static void orinoco_set_multicast_list(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0) {
@@ -307,7 +318,7 @@ static void orinoco_set_multicast_list(struct net_device *dev)
static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
if ((new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU))
return -EINVAL;
@@ -328,7 +339,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu)
static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw;
int err = 0;
@@ -355,7 +366,8 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
- if (!netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
+ if (!netif_carrier_ok(dev) ||
+ (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
@@ -518,7 +530,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u16 fid = hermes_read_regn(hw, ALLOCFID);
if (fid != priv->txfid) {
@@ -533,7 +545,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw)
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
stats->tx_packets++;
@@ -545,7 +557,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw)
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 fid = hermes_read_regn(hw, TXCOMPLFID);
u16 status;
@@ -601,7 +613,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
static void orinoco_tx_timeout(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct hermes *hw = &priv->hw;
@@ -650,7 +662,7 @@ static void orinoco_stat_gather(struct net_device *dev,
struct sk_buff *skb,
struct hermes_rx_descriptor *desc)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
/* Using spy support with lots of Rx packets, like in an
* infrastructure (AP), will really slow down everything, because
@@ -687,7 +699,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
int err;
int len;
struct sk_buff *skb;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
hermes_t *hw = &priv->hw;
@@ -778,7 +790,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
struct iw_statistics *wstats = &priv->wstats;
struct sk_buff *skb = NULL;
@@ -816,7 +828,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
}
/* Handle frames in monitor mode */
- if (priv->iw_mode == IW_MODE_MONITOR) {
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
orinoco_rx_monitor(dev, rxfid, desc);
goto out;
}
@@ -902,7 +914,7 @@ static void orinoco_rx(struct net_device *dev,
struct hermes_rx_descriptor *desc,
struct sk_buff *skb)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats;
u16 status, fc;
int length;
@@ -1016,8 +1028,8 @@ static void orinoco_rx(struct net_device *dev,
static void orinoco_rx_isr_tasklet(unsigned long data)
{
- struct net_device *dev = (struct net_device *) data;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = (struct orinoco_private *) data;
+ struct net_device *dev = priv->ndev;
struct orinoco_rx_data *rx_data, *temp;
struct hermes_rx_descriptor *desc;
struct sk_buff *skb;
@@ -1260,9 +1272,81 @@ static void orinoco_send_wevents(struct work_struct *work)
orinoco_unlock(priv, &flags);
}
+static void qbuf_scan(struct orinoco_private *priv, void *buf,
+ int len, int type)
+{
+ struct orinoco_scan_data *sd;
+ unsigned long flags;
+
+ sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+ sd->buf = buf;
+ sd->len = len;
+ sd->type = type;
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_add_tail(&sd->list, &priv->scan_list);
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ schedule_work(&priv->process_scan);
+}
+
+static void qabort_scan(struct orinoco_private *priv)
+{
+ struct orinoco_scan_data *sd;
+ unsigned long flags;
+
+ sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
+ sd->len = -1; /* Abort */
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_add_tail(&sd->list, &priv->scan_list);
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ schedule_work(&priv->process_scan);
+}
+
+static void orinoco_process_scan_results(struct work_struct *work)
+{
+ struct orinoco_private *priv =
+ container_of(work, struct orinoco_private, process_scan);
+ struct orinoco_scan_data *sd, *temp;
+ unsigned long flags;
+ void *buf;
+ int len;
+ int type;
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+
+ buf = sd->buf;
+ len = sd->len;
+ type = sd->type;
+
+ list_del(&sd->list);
+ kfree(sd);
+
+ if (len > 0) {
+ if (type == HERMES_INQ_CHANNELINFO)
+ orinoco_add_extscan_result(priv, buf, len);
+ else
+ orinoco_add_hostscan_results(priv, buf, len);
+
+ kfree(buf);
+ } else if (priv->scan_request) {
+ /* Either abort or complete the scan */
+ cfg80211_scan_done(priv->scan_request, (len < 0));
+ priv->scan_request = NULL;
+ }
+
+ spin_lock_irqsave(&priv->scan_lock, flags);
+ }
+ spin_unlock_irqrestore(&priv->scan_lock, flags);
+}
+
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u16 infofid;
struct {
__le16 len;
@@ -1327,7 +1411,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
u16 newstatus;
int connected;
- if (priv->iw_mode == IW_MODE_MONITOR)
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
break;
if (len != sizeof(linkstatus)) {
@@ -1346,7 +1430,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
* the hostscan frame can be requested. */
if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
- priv->has_hostscan && priv->scan_inprogress) {
+ priv->has_hostscan && priv->scan_request) {
hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
break;
}
@@ -1372,7 +1456,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
}
break;
case HERMES_INQ_SCAN:
- if (!priv->scan_inprogress && priv->bssid_fixed &&
+ if (!priv->scan_request && priv->bssid_fixed &&
priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
schedule_work(&priv->join_work);
break;
@@ -1382,30 +1466,30 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
case HERMES_INQ_HOSTSCAN_SYMBOL: {
/* Result of a scanning. Contains information about
* cells in the vicinity - Jean II */
- union iwreq_data wrqu;
unsigned char *buf;
- /* Scan is no longer in progress */
- priv->scan_inprogress = 0;
-
/* Sanity check */
if (len > 4096) {
printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
dev->name, len);
+ qabort_scan(priv);
break;
}
/* Allocate buffer for results */
buf = kmalloc(len, GFP_ATOMIC);
- if (buf == NULL)
+ if (buf == NULL) {
/* No memory, so can't printk()... */
+ qabort_scan(priv);
break;
+ }
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
infofid, sizeof(info));
if (err) {
kfree(buf);
+ qabort_scan(priv);
break;
}
@@ -1419,24 +1503,14 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
}
#endif /* ORINOCO_DEBUG */
- if (orinoco_process_scan_results(priv, buf, len) == 0) {
- /* Send an empty event to user space.
- * We don't send the received data on the event because
- * it would require us to do complex transcoding, and
- * we want to minimise the work done in the irq handler
- * Use a request to extract the data - Jean II */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
- }
- kfree(buf);
+ qbuf_scan(priv, buf, len, type);
}
break;
case HERMES_INQ_CHANNELINFO:
{
struct agere_ext_scan_info *bss;
- if (!priv->scan_inprogress) {
+ if (!priv->scan_request) {
printk(KERN_DEBUG "%s: Got chaninfo without scan, "
"len=%d\n", dev->name, len);
break;
@@ -1444,25 +1518,12 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* An empty result indicates that the scan is complete */
if (len == 0) {
- union iwreq_data wrqu;
-
- /* Scan is no longer in progress */
- priv->scan_inprogress = 0;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+ qbuf_scan(priv, NULL, len, type);
break;
}
/* Sanity check */
- else if (len > sizeof(*bss)) {
- printk(KERN_WARNING
- "%s: Ext scan results too large (%d bytes). "
- "Truncating results to %zd bytes.\n",
- dev->name, len, sizeof(*bss));
- len = sizeof(*bss);
- } else if (len < (offsetof(struct agere_ext_scan_info,
+ else if (len < (offsetof(struct agere_ext_scan_info,
data) + 2)) {
/* Drop this result now so we don't have to
* keep checking later */
@@ -1472,21 +1533,18 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break;
}
- bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+ bss = kmalloc(len, GFP_ATOMIC);
if (bss == NULL)
break;
/* Read scan data */
err = hermes_bap_pread(hw, IRQ_BAP, (void *) bss, len,
infofid, sizeof(info));
- if (err) {
+ if (err)
kfree(bss);
- break;
- }
-
- orinoco_add_ext_scan_result(priv, bss);
+ else
+ qbuf_scan(priv, bss, len, type);
- kfree(bss);
break;
}
case HERMES_INQ_SEC_STAT_AGERE:
@@ -1501,6 +1559,8 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
/* We don't actually do anything about it */
break;
}
+
+ return;
}
static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
@@ -1513,15 +1573,15 @@ static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw)
/* Internal hardware control routines */
/********************************************************************/
-int __orinoco_up(struct net_device *dev)
+static int __orinoco_up(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device *dev = priv->ndev;
struct hermes *hw = &priv->hw;
int err;
netif_carrier_off(dev); /* just to make sure */
- err = __orinoco_program_rids(dev);
+ err = __orinoco_commit(priv);
if (err) {
printk(KERN_ERR "%s: Error %d configuring card\n",
dev->name, err);
@@ -1541,11 +1601,10 @@ int __orinoco_up(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL(__orinoco_up);
-int __orinoco_down(struct net_device *dev)
+static int __orinoco_down(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device *dev = priv->ndev;
struct hermes *hw = &priv->hw;
int err;
@@ -1573,31 +1632,9 @@ int __orinoco_down(struct net_device *dev)
return 0;
}
-EXPORT_SYMBOL(__orinoco_down);
-static int orinoco_allocate_fid(struct net_device *dev)
+static int orinoco_reinit_firmware(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
- if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
- /* Try workaround for old Symbol firmware bug */
- priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
- err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
-
- printk(KERN_WARNING "%s: firmware ALLOC bug detected "
- "(old Symbol firmware?). Work around %s\n",
- dev->name, err ? "failed!" : "ok.");
- }
-
- return err;
-}
-
-int orinoco_reinit_firmware(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
struct hermes *hw = &priv->hw;
int err;
@@ -1608,246 +1645,15 @@ int orinoco_reinit_firmware(struct net_device *dev)
priv->do_fw_download = 0;
}
if (!err)
- err = orinoco_allocate_fid(dev);
+ err = orinoco_hw_allocate_fid(priv);
return err;
}
-EXPORT_SYMBOL(orinoco_reinit_firmware);
-
-int __orinoco_program_rids(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- int err;
- struct hermes_idstring idbuf;
-
- /* Set the MAC address */
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting MAC address\n",
- dev->name, err);
- return err;
- }
-
- /* Set up the link mode */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
- priv->port_type);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting port type\n",
- dev->name, err);
- return err;
- }
- /* Set the channel/frequency */
- if (priv->channel != 0 && priv->iw_mode != IW_MODE_INFRA) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFOWNCHANNEL,
- priv->channel);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting channel %d\n",
- dev->name, err, priv->channel);
- return err;
- }
- }
-
- if (priv->has_ibss) {
- u16 createibss;
-
- if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
- printk(KERN_WARNING "%s: This firmware requires an "
- "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
- /* With wvlan_cs, in this case, we would crash.
- * hopefully, this driver will behave better...
- * Jean II */
- createibss = 0;
- } else {
- createibss = priv->createibss;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFCREATEIBSS,
- createibss);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set the desired BSSID */
- err = __orinoco_hw_set_wap(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting AP address\n",
- dev->name, err);
- return err;
- }
- /* Set the desired ESSID */
- idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
- memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
- /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
- dev->name, err);
- return err;
- }
-
- /* Set the station name */
- idbuf.len = cpu_to_le16(strlen(priv->nick));
- memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
- err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting nickname\n",
- dev->name, err);
- return err;
- }
-
- /* Set AP density */
- if (priv->has_sensitivity) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSYSTEMSCALE,
- priv->ap_density);
- if (err) {
- printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
- "Disabling sensitivity control\n",
- dev->name, err);
-
- priv->has_sensitivity = 0;
- }
- }
-
- /* Set RTS threshold */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
- dev->name, err);
- return err;
- }
-
- /* Set fragmentation threshold or MWO robustness */
- if (priv->has_mwo)
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- priv->mwo_robust);
- else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- priv->frag_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting fragmentation\n",
- dev->name, err);
- return err;
- }
-
- /* Set bitrate */
- err = __orinoco_hw_set_bitrate(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting bitrate\n",
- dev->name, err);
- return err;
- }
-
- /* Set power management */
- if (priv->has_pm) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMENABLED,
- priv->pm_on);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMULTICASTRECEIVE,
- priv->pm_mcast);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set preamble - only for Symbol so far... */
- if (priv->has_preamble) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- priv->preamble);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting preamble\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set up encryption */
- if (priv->has_wep || priv->has_wpa) {
- err = __orinoco_hw_setup_enc(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d activating encryption\n",
- dev->name, err);
- return err;
- }
- }
-
- if (priv->iw_mode == IW_MODE_MONITOR) {
- /* Enable monitor mode */
- dev->type = ARPHRD_IEEE80211;
- err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_MONITOR, 0, NULL);
- } else {
- /* Disable monitor mode */
- dev->type = ARPHRD_ETHER;
- err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_STOP, 0, NULL);
- }
- if (err)
- return err;
-
- /* Set promiscuity / multicast*/
- priv->promiscuous = 0;
- priv->mc_count = 0;
-
- /* FIXME: what about netif_tx_lock */
- __orinoco_set_multicast_list(dev);
-
- return 0;
-}
-/* FIXME: return int? */
-static void
+static int
__orinoco_set_multicast_list(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
int promisc, mc_count;
@@ -1864,6 +1670,8 @@ __orinoco_set_multicast_list(struct net_device *dev)
err = __orinoco_hw_set_multicast_list(priv, dev->mc_list, mc_count,
promisc);
+
+ return err;
}
/* This must be called from user context, without locks held - use
@@ -1896,9 +1704,11 @@ void orinoco_reset(struct work_struct *work)
orinoco_unlock(priv, &flags);
- /* Scanning support: Cleanup of driver struct */
- orinoco_clear_scan_results(priv, 0);
- priv->scan_inprogress = 0;
+ /* Scanning support: Notify scan cancellation */
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, 1);
+ priv->scan_request = NULL;
+ }
if (priv->hard_reset) {
err = (*priv->hard_reset)(priv);
@@ -1909,7 +1719,7 @@ void orinoco_reset(struct work_struct *work)
}
}
- err = orinoco_reinit_firmware(dev);
+ err = orinoco_reinit_firmware(priv);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
dev->name, err);
@@ -1924,7 +1734,7 @@ void orinoco_reset(struct work_struct *work)
/* priv->open or priv->hw_unavailable might have changed while
* we dropped the lock */
if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
+ err = __orinoco_up(priv);
if (err) {
printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
dev->name, err);
@@ -1941,6 +1751,64 @@ void orinoco_reset(struct work_struct *work)
printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
}
+static int __orinoco_commit(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ int err = 0;
+
+ err = orinoco_hw_program_rids(priv);
+
+ /* FIXME: what about netif_tx_lock */
+ (void) __orinoco_set_multicast_list(dev);
+
+ return err;
+}
+
+/* Ensures configuration changes are applied. May result in a reset.
+ * The caller should hold priv->lock
+ */
+int orinoco_commit(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ hermes_t *hw = &priv->hw;
+ int err;
+
+ if (priv->broken_disableport) {
+ schedule_work(&priv->reset_work);
+ return 0;
+ }
+
+ err = hermes_disable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to disable port "
+ "while reconfiguring card\n", dev->name);
+ priv->broken_disableport = 1;
+ goto out;
+ }
+
+ err = __orinoco_commit(priv);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+ dev->name);
+ goto out;
+ }
+
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+ dev->name);
+ goto out;
+ }
+
+ out:
+ if (err) {
+ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
+ schedule_work(&priv->reset_work);
+ err = 0;
+ }
+ return err;
+}
+
/********************************************************************/
/* Interrupt handler */
/********************************************************************/
@@ -1960,8 +1828,8 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
irqreturn_t orinoco_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = dev_id;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = dev_id;
+ struct net_device *dev = priv->ndev;
hermes_t *hw = &priv->hw;
int count = MAX_IRQLOOPS_PER_IRQ;
u16 evstat, events;
@@ -2096,227 +1964,12 @@ static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
/* Initialization */
/********************************************************************/
-struct comp_id {
- u16 id, variant, major, minor;
-} __attribute__ ((packed));
-
-static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
-{
- if (nic_id->id < 0x8000)
- return FIRMWARE_TYPE_AGERE;
- else if (nic_id->id == 0x8000 && nic_id->major == 0)
- return FIRMWARE_TYPE_SYMBOL;
- else
- return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties */
-static int determine_firmware(struct net_device *dev)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- int err;
- struct comp_id nic_id, sta_id;
- unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
-
- /* Get the hardware version */
- err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
- if (err) {
- printk(KERN_ERR "%s: Cannot read hardware identity: error %d\n",
- dev->name, err);
- return err;
- }
-
- le16_to_cpus(&nic_id.id);
- le16_to_cpus(&nic_id.variant);
- le16_to_cpus(&nic_id.major);
- le16_to_cpus(&nic_id.minor);
- printk(KERN_DEBUG "%s: Hardware identity %04x:%04x:%04x:%04x\n",
- dev->name, nic_id.id, nic_id.variant,
- nic_id.major, nic_id.minor);
-
- priv->firmware_type = determine_firmware_type(&nic_id);
-
- /* Get the firmware version */
- err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
- if (err) {
- printk(KERN_ERR "%s: Cannot read station identity: error %d\n",
- dev->name, err);
- return err;
- }
-
- le16_to_cpus(&sta_id.id);
- le16_to_cpus(&sta_id.variant);
- le16_to_cpus(&sta_id.major);
- le16_to_cpus(&sta_id.minor);
- printk(KERN_DEBUG "%s: Station identity %04x:%04x:%04x:%04x\n",
- dev->name, sta_id.id, sta_id.variant,
- sta_id.major, sta_id.minor);
-
- switch (sta_id.id) {
- case 0x15:
- printk(KERN_ERR "%s: Primary firmware is active\n",
- dev->name);
- return -ENODEV;
- case 0x14b:
- printk(KERN_ERR "%s: Tertiary firmware is active\n",
- dev->name);
- return -ENODEV;
- case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
- case 0x21: /* Symbol Spectrum24 Trilogy */
- break;
- default:
- printk(KERN_NOTICE "%s: Unknown station ID, please report\n",
- dev->name);
- break;
- }
-
- /* Default capabilities */
- priv->has_sensitivity = 1;
- priv->has_mwo = 0;
- priv->has_preamble = 0;
- priv->has_port3 = 1;
- priv->has_ibss = 1;
- priv->has_wep = 0;
- priv->has_big_wep = 0;
- priv->has_alt_txcntl = 0;
- priv->has_ext_scan = 0;
- priv->has_wpa = 0;
- priv->do_fw_download = 0;
-
- /* Determine capabilities from the firmware version */
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
- ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
-
- firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
- priv->has_ibss = (firmver >= 0x60006);
- priv->has_wep = (firmver >= 0x40020);
- priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
- Gold cards from the others? */
- priv->has_mwo = (firmver >= 0x60000);
- priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
- priv->ibss_port = 1;
- priv->has_hostscan = (firmver >= 0x8000a);
- priv->do_fw_download = 1;
- priv->broken_monitor = (firmver >= 0x80000);
- priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_wpa = (firmver >= 0x9002a);
- /* Tested with Agere firmware :
- * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
- * Tested CableTron firmware : 4.32 => Anton */
- break;
- case FIRMWARE_TYPE_SYMBOL:
- /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
- /* Intel MAC : 00:02:B3:* */
- /* 3Com MAC : 00:50:DA:* */
- memset(tmp, 0, sizeof(tmp));
- /* Get the Symbol firmware version */
- err = hermes_read_ltv(hw, USER_BAP,
- HERMES_RID_SECONDARYVERSION_SYMBOL,
- SYMBOL_MAX_VER_LEN, NULL, &tmp);
- if (err) {
- printk(KERN_WARNING
- "%s: Error %d reading Symbol firmware info. "
- "Wildly guessing capabilities...\n",
- dev->name, err);
- firmver = 0;
- tmp[0] = '\0';
- } else {
- /* The firmware revision is a string, the format is
- * something like : "V2.20-01".
- * Quick and dirty parsing... - Jean II
- */
- firmver = ((tmp[1] - '0') << 16)
- | ((tmp[3] - '0') << 12)
- | ((tmp[4] - '0') << 8)
- | ((tmp[6] - '0') << 4)
- | (tmp[7] - '0');
-
- tmp[SYMBOL_MAX_VER_LEN] = '\0';
- }
-
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Symbol %s", tmp);
-
- priv->has_ibss = (firmver >= 0x20000);
- priv->has_wep = (firmver >= 0x15012);
- priv->has_big_wep = (firmver >= 0x20000);
- priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
- (firmver >= 0x29000 && firmver < 0x30000) ||
- firmver >= 0x31000;
- priv->has_preamble = (firmver >= 0x20000);
- priv->ibss_port = 4;
-
- /* Symbol firmware is found on various cards, but
- * there has been no attempt to check firmware
- * download on non-spectrum_cs based cards.
- *
- * Given that the Agere firmware download works
- * differently, we should avoid doing a firmware
- * download with the Symbol algorithm on non-spectrum
- * cards.
- *
- * For now we can identify a spectrum_cs based card
- * because it has a firmware reset function.
- */
- priv->do_fw_download = (priv->stop_fw != NULL);
-
- priv->broken_disableport = (firmver == 0x25013) ||
- (firmver >= 0x30000 && firmver <= 0x31000);
- priv->has_hostscan = (firmver >= 0x31001) ||
- (firmver >= 0x29057 && firmver < 0x30000);
- /* Tested with Intel firmware : 0x20015 => Jean II */
- /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
- break;
- case FIRMWARE_TYPE_INTERSIL:
- /* D-Link, Linksys, Adtron, ZoomAir, and many others...
- * Samsung, Compaq 100/200 and Proxim are slightly
- * different and less well tested */
- /* D-Link MAC : 00:40:05:* */
- /* Addtron MAC : 00:90:D1:* */
- snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
- "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
- sta_id.variant);
-
- firmver = ((unsigned long)sta_id.major << 16) |
- ((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
- priv->has_ibss = (firmver >= 0x000700); /* FIXME */
- priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
- priv->has_pm = (firmver >= 0x000700);
- priv->has_hostscan = (firmver >= 0x010301);
-
- if (firmver >= 0x000800)
- priv->ibss_port = 0;
- else {
- printk(KERN_NOTICE "%s: Intersil firmware earlier "
- "than v0.8.x - several features not supported\n",
- dev->name);
- priv->ibss_port = 1;
- }
- break;
- }
- printk(KERN_DEBUG "%s: Firmware determined as %s\n", dev->name,
- priv->fw_name);
-
- return 0;
-}
-
-static int orinoco_init(struct net_device *dev)
+int orinoco_init(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct device *dev = priv->dev;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
hermes_t *hw = &priv->hw;
int err = 0;
- struct hermes_idstring nickbuf;
- u16 reclen;
- int len;
/* No need to lock, the hw_unavailable flag is already set in
* alloc_orinocodev() */
@@ -2325,15 +1978,14 @@ static int orinoco_init(struct net_device *dev)
/* Initialize the firmware */
err = hermes_init(hw);
if (err != 0) {
- printk(KERN_ERR "%s: failed to initialize firmware (err = %d)\n",
- dev->name, err);
+ dev_err(dev, "Failed to initialize firmware (err = %d)\n",
+ err);
goto out;
}
- err = determine_firmware(dev);
+ err = determine_fw_capabilities(priv);
if (err != 0) {
- printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
- dev->name);
+ dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
}
@@ -2347,147 +1999,41 @@ static int orinoco_init(struct net_device *dev)
priv->do_fw_download = 0;
/* Check firmware version again */
- err = determine_firmware(dev);
+ err = determine_fw_capabilities(priv);
if (err != 0) {
- printk(KERN_ERR "%s: Incompatible firmware, aborting\n",
- dev->name);
+ dev_err(dev, "Incompatible firmware, aborting\n");
goto out;
}
}
if (priv->has_port3)
- printk(KERN_DEBUG "%s: Ad-hoc demo mode supported\n",
- dev->name);
+ dev_info(dev, "Ad-hoc demo mode supported\n");
if (priv->has_ibss)
- printk(KERN_DEBUG "%s: IEEE standard IBSS ad-hoc mode supported\n",
- dev->name);
- if (priv->has_wep) {
- printk(KERN_DEBUG "%s: WEP supported, %s-bit key\n", dev->name,
- priv->has_big_wep ? "104" : "40");
- }
+ dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
+ if (priv->has_wep)
+ dev_info(dev, "WEP supported, %s-bit key\n",
+ priv->has_big_wep ? "104" : "40");
if (priv->has_wpa) {
- printk(KERN_DEBUG "%s: WPA-PSK supported\n", dev->name);
+ dev_info(dev, "WPA-PSK supported\n");
if (orinoco_mic_init(priv)) {
- printk(KERN_ERR "%s: Failed to setup MIC crypto "
- "algorithm. Disabling WPA support\n", dev->name);
+ dev_err(dev, "Failed to setup MIC crypto algorithm. "
+ "Disabling WPA support\n");
priv->has_wpa = 0;
}
}
- /* Now we have the firmware capabilities, allocate appropiate
- * sized scan buffers */
- if (orinoco_bss_data_allocate(priv))
- goto out;
- orinoco_bss_data_init(priv);
-
- /* Get the MAC address */
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- ETH_ALEN, NULL, dev->dev_addr);
- if (err) {
- printk(KERN_WARNING "%s: failed to read MAC address!\n",
- dev->name);
- goto out;
- }
-
- printk(KERN_DEBUG "%s: MAC address %pM\n",
- dev->name, dev->dev_addr);
-
- /* Get the station name */
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- sizeof(nickbuf), &reclen, &nickbuf);
- if (err) {
- printk(KERN_ERR "%s: failed to read station name\n",
- dev->name);
- goto out;
- }
- if (nickbuf.len)
- len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
- else
- len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
- memcpy(priv->nick, &nickbuf.val, len);
- priv->nick[len] = '\0';
-
- printk(KERN_DEBUG "%s: Station name \"%s\"\n", dev->name, priv->nick);
-
- err = orinoco_allocate_fid(dev);
- if (err) {
- printk(KERN_ERR "%s: failed to allocate NIC buffer!\n",
- dev->name);
- goto out;
- }
-
- /* Get allowed channels */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
- &priv->channel_mask);
- if (err) {
- printk(KERN_ERR "%s: failed to read channel list!\n",
- dev->name);
- goto out;
- }
-
- /* Get initial AP density */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
- &priv->ap_density);
- if (err || priv->ap_density < 1 || priv->ap_density > 3)
- priv->has_sensitivity = 0;
-
- /* Get initial RTS threshold */
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- &priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: failed to read RTS threshold!\n",
- dev->name);
+ err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
+ if (err)
goto out;
- }
- /* Get initial fragmentation settings */
- if (priv->has_mwo)
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- &priv->mwo_robust);
- else
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- &priv->frag_thresh);
+ err = orinoco_hw_allocate_fid(priv);
if (err) {
- printk(KERN_ERR "%s: failed to read fragmentation settings!\n",
- dev->name);
+ dev_err(dev, "Failed to allocate NIC buffer!\n");
goto out;
}
- /* Power management setup */
- if (priv->has_pm) {
- priv->pm_on = 0;
- priv->pm_mcast = 1;
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- &priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: failed to read power management period!\n",
- dev->name);
- goto out;
- }
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- &priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: failed to read power management timeout!\n",
- dev->name);
- goto out;
- }
- }
-
- /* Preamble setup */
- if (priv->has_preamble) {
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- &priv->preamble);
- if (err)
- goto out;
- }
-
/* Set up the default configuration */
- priv->iw_mode = IW_MODE_INFRA;
+ priv->iw_mode = NL80211_IFTYPE_STATION;
/* By default use IEEE/IBSS ad-hoc mode if we have it */
priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
set_port_type(priv);
@@ -2502,20 +2048,25 @@ static int orinoco_init(struct net_device *dev)
priv->wpa_ie_len = 0;
priv->wpa_ie = NULL;
+ if (orinoco_wiphy_register(wiphy)) {
+ err = -ENODEV;
+ goto out;
+ }
+
/* Make the hardware available, as long as it hasn't been
* removed elsewhere (e.g. by PCMCIA hot unplug) */
spin_lock_irq(&priv->lock);
priv->hw_unavailable--;
spin_unlock_irq(&priv->lock);
- printk(KERN_DEBUG "%s: ready\n", dev->name);
+ dev_dbg(dev, "Ready\n");
out:
return err;
}
+EXPORT_SYMBOL(orinoco_init);
static const struct net_device_ops orinoco_netdev_ops = {
- .ndo_init = orinoco_init,
.ndo_open = orinoco_open,
.ndo_stop = orinoco_stop,
.ndo_start_xmit = orinoco_xmit,
@@ -2527,40 +2078,64 @@ static const struct net_device_ops orinoco_netdev_ops = {
.ndo_get_stats = orinoco_get_stats,
};
-struct net_device
+/* Allocate private data.
+ *
+ * This driver has a number of structures associated with it
+ * netdev - Net device structure for each network interface
+ * wiphy - structure associated with wireless phy
+ * wireless_dev (wdev) - structure for each wireless interface
+ * hw - structure for hermes chip info
+ * card - card specific structure for use by the card driver
+ * (airport, orinoco_cs)
+ * priv - orinoco private data
+ * device - generic linux device structure
+ *
+ * +---------+ +---------+
+ * | wiphy | | netdev |
+ * | +-------+ | +-------+
+ * | | priv | | | wdev |
+ * | | +-----+ +-+-------+
+ * | | | hw |
+ * | +-+-----+
+ * | | card |
+ * +-+-------+
+ *
+ * priv has a link to netdev and device
+ * wdev has a link to wiphy
+ */
+struct orinoco_private
*alloc_orinocodev(int sizeof_card,
struct device *device,
int (*hard_reset)(struct orinoco_private *),
int (*stop_fw)(struct orinoco_private *, int))
{
- struct net_device *dev;
struct orinoco_private *priv;
+ struct wiphy *wiphy;
- dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card);
- if (!dev)
+ /* allocate wiphy
+ * NOTE: We only support a single virtual interface
+ * but this may change when monitor mode is added
+ */
+ wiphy = wiphy_new(&orinoco_cfg_ops,
+ sizeof(struct orinoco_private) + sizeof_card);
+ if (!wiphy)
return NULL;
- priv = netdev_priv(dev);
- priv->ndev = dev;
+
+ priv = wiphy_priv(wiphy);
+ priv->dev = device;
+
if (sizeof_card)
priv->card = (void *)((unsigned long)priv
+ sizeof(struct orinoco_private));
else
priv->card = NULL;
- priv->dev = device;
- /* Setup / override net_device fields */
- dev->netdev_ops = &orinoco_netdev_ops;
- dev->watchdog_timeo = HZ; /* 1 second timeout */
- dev->ethtool_ops = &orinoco_ethtool_ops;
- dev->wireless_handlers = &orinoco_handler_def;
+ orinoco_wiphy_init(wiphy);
+
#ifdef WIRELESS_SPY
priv->wireless_data.spy_data = &priv->spy_data;
- dev->wireless_data = &priv->wireless_data;
#endif
- /* Reserve space in skb for the SNAP header */
- dev->hard_header_len += ENCAPS_OVERHEAD;
-
/* Set up default callbacks */
priv->hard_reset = hard_reset;
priv->stop_fw = stop_fw;
@@ -2576,9 +2151,12 @@ struct net_device
INIT_LIST_HEAD(&priv->rx_list);
tasklet_init(&priv->rx_tasklet, orinoco_rx_isr_tasklet,
- (unsigned long) dev);
+ (unsigned long) priv);
+
+ spin_lock_init(&priv->scan_lock);
+ INIT_LIST_HEAD(&priv->scan_list);
+ INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
- netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
@@ -2589,14 +2167,91 @@ struct net_device
/* Register PM notifiers */
orinoco_register_pm_notifier(priv);
- return dev;
+ return priv;
}
EXPORT_SYMBOL(alloc_orinocodev);
-void free_orinocodev(struct net_device *dev)
+/* We can only support a single interface. We provide a separate
+ * function to set it up to distinguish between hardware
+ * initialisation and interface setup.
+ *
+ * The base_addr and irq parameters are passed on to netdev for use
+ * with SIOCGIFMAP.
+ */
+int orinoco_if_add(struct orinoco_private *priv,
+ unsigned long base_addr,
+ unsigned int irq)
+{
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct wireless_dev *wdev;
+ struct net_device *dev;
+ int ret;
+
+ dev = alloc_etherdev(sizeof(struct wireless_dev));
+
+ if (!dev)
+ return -ENOMEM;
+
+ /* Initialise wireless_dev */
+ wdev = netdev_priv(dev);
+ wdev->wiphy = wiphy;
+ wdev->iftype = NL80211_IFTYPE_STATION;
+
+ /* Setup / override net_device fields */
+ dev->ieee80211_ptr = wdev;
+ dev->netdev_ops = &orinoco_netdev_ops;
+ dev->watchdog_timeo = HZ; /* 1 second timeout */
+ dev->ethtool_ops = &orinoco_ethtool_ops;
+ dev->wireless_handlers = &orinoco_handler_def;
+#ifdef WIRELESS_SPY
+ dev->wireless_data = &priv->wireless_data;
+#endif
+ /* we use the default eth_mac_addr for setting the MAC addr */
+
+ /* Reserve space in skb for the SNAP header */
+ dev->hard_header_len += ENCAPS_OVERHEAD;
+
+ netif_carrier_off(dev);
+
+ memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
+
+ dev->base_addr = base_addr;
+ dev->irq = irq;
+
+ SET_NETDEV_DEV(dev, priv->dev);
+ ret = register_netdev(dev);
+ if (ret)
+ goto fail;
+
+ priv->ndev = dev;
+
+ /* Report what we've done */
+ dev_dbg(priv->dev, "Registerred interface %s.\n", dev->name);
+
+ return 0;
+
+ fail:
+ free_netdev(dev);
+ return ret;
+}
+EXPORT_SYMBOL(orinoco_if_add);
+
+void orinoco_if_del(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+
+ unregister_netdev(dev);
+ free_netdev(dev);
+}
+EXPORT_SYMBOL(orinoco_if_del);
+
+void free_orinocodev(struct orinoco_private *priv)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct wiphy *wiphy = priv_to_wiphy(priv);
struct orinoco_rx_data *rx_data, *temp;
+ struct orinoco_scan_data *sd, *sdtemp;
+
+ wiphy_unregister(wiphy);
/* If the tasklet is scheduled when we call tasklet_kill it
* will run one final time. However the tasklet will only
@@ -2612,21 +2267,80 @@ void free_orinocodev(struct net_device *dev)
kfree(rx_data);
}
+ cancel_work_sync(&priv->process_scan);
+ /* Explicitly drain priv->scan_list */
+ list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
+ list_del(&sd->list);
+
+ if ((sd->len > 0) && sd->buf)
+ kfree(sd->buf);
+ kfree(sd);
+ }
+
orinoco_unregister_pm_notifier(priv);
orinoco_uncache_fw(priv);
priv->wpa_ie_len = 0;
kfree(priv->wpa_ie);
orinoco_mic_free(priv);
- orinoco_bss_data_free(priv);
- free_netdev(dev);
+ wiphy_free(wiphy);
}
EXPORT_SYMBOL(free_orinocodev);
+int orinoco_up(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ err = orinoco_reinit_firmware(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
+ dev->name, err);
+ goto exit;
+ }
+
+ netif_device_attach(dev);
+ priv->hw_unavailable--;
+
+ if (priv->open && !priv->hw_unavailable) {
+ err = __orinoco_up(priv);
+ if (err)
+ printk(KERN_ERR "%s: Error %d restarting card\n",
+ dev->name, err);
+ }
+
+exit:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(orinoco_up);
+
+void orinoco_down(struct orinoco_private *priv)
+{
+ struct net_device *dev = priv->ndev;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ err = __orinoco_down(priv);
+ if (err)
+ printk(KERN_WARNING "%s: Error %d downing interface\n",
+ dev->name, err);
+
+ netif_device_detach(dev);
+ priv->hw_unavailable++;
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(orinoco_down);
+
static void orinoco_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
diff --git a/drivers/net/wireless/orinoco/main.h b/drivers/net/wireless/orinoco/main.h
index af2bae4fe39..21ab36cd76c 100644
--- a/drivers/net/wireless/orinoco/main.h
+++ b/drivers/net/wireless/orinoco/main.h
@@ -29,10 +29,9 @@ struct net_device;
struct work_struct;
void set_port_type(struct orinoco_private *priv);
-int __orinoco_program_rids(struct net_device *dev);
+int orinoco_commit(struct orinoco_private *priv);
void orinoco_reset(struct work_struct *work);
-
/* Information element helpers - find a home for these... */
static inline u8 *orinoco_get_ie(u8 *data, size_t len,
enum ieee80211_eid eid)
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index 8e5a72cc297..5f4f5c9eef7 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -14,6 +14,7 @@
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes.h"
@@ -47,18 +48,6 @@ typedef enum {
FIRMWARE_TYPE_SYMBOL
} fwtype_t;
-struct bss_element {
- union hermes_scan_info bss;
- unsigned long last_scanned;
- struct list_head list;
-};
-
-struct xbss_element {
- struct agere_ext_scan_info bss;
- unsigned long last_scanned;
- struct list_head list;
-};
-
struct firmware;
struct orinoco_private {
@@ -67,6 +56,10 @@ struct orinoco_private {
int (*hard_reset)(struct orinoco_private *);
int (*stop_fw)(struct orinoco_private *, int);
+ struct ieee80211_supported_band band;
+ struct ieee80211_channel channels[14];
+ u32 cipher_suites[3];
+
/* Synchronisation stuff */
spinlock_t lock;
int hw_unavailable;
@@ -116,7 +109,7 @@ struct orinoco_private {
unsigned int broken_monitor:1;
/* Configuration paramaters */
- u32 iw_mode;
+ enum nl80211_iftype iw_mode;
int prefer_port3;
u16 encode_alg, wep_restrict, tx_key;
struct orinoco_key keys[ORINOCO_MAX_KEYS];
@@ -140,12 +133,10 @@ struct orinoco_private {
int promiscuous, mc_count;
/* Scanning support */
- struct list_head bss_list;
- struct list_head bss_free_list;
- void *bss_xbss_data;
-
- int scan_inprogress; /* Scan pending... */
- u32 scan_mode; /* Type of scan done */
+ struct cfg80211_scan_request *scan_request;
+ struct work_struct process_scan;
+ struct list_head scan_list;
+ spinlock_t scan_lock; /* protects the scan list */
/* WPA support */
u8 *wpa_ie;
@@ -182,14 +173,18 @@ extern int orinoco_debug;
/* Exported prototypes */
/********************************************************************/
-extern struct net_device *alloc_orinocodev(
+extern struct orinoco_private *alloc_orinocodev(
int sizeof_card, struct device *device,
int (*hard_reset)(struct orinoco_private *),
int (*stop_fw)(struct orinoco_private *, int));
-extern void free_orinocodev(struct net_device *dev);
-extern int __orinoco_up(struct net_device *dev);
-extern int __orinoco_down(struct net_device *dev);
-extern int orinoco_reinit_firmware(struct net_device *dev);
+extern void free_orinocodev(struct orinoco_private *priv);
+extern int orinoco_init(struct orinoco_private *priv);
+extern int orinoco_if_add(struct orinoco_private *priv,
+ unsigned long base_addr,
+ unsigned int irq);
+extern void orinoco_if_del(struct orinoco_private *priv);
+extern int orinoco_up(struct orinoco_private *priv);
+extern void orinoco_down(struct orinoco_private *priv);
extern irqreturn_t orinoco_interrupt(int irq, void *dev_id);
/********************************************************************/
@@ -215,4 +210,10 @@ static inline void orinoco_unlock(struct orinoco_private *priv,
spin_unlock_irqrestore(&priv->lock, *flags);
}
+/*** Navigate from net_device to orinoco_private ***/
+static inline struct orinoco_private *ndev_priv(struct net_device *dev)
+{
+ struct wireless_dev *wdev = netdev_priv(dev);
+ return wdev_priv(wdev);
+}
#endif /* _ORINOCO_H */
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index b381aed24d7..38c1c9d2abb 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -106,26 +106,24 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
static int
orinoco_cs_probe(struct pcmcia_device *link)
{
- struct net_device *dev;
struct orinoco_private *priv;
struct orinoco_pccard *card;
- dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
- orinoco_cs_hard_reset, NULL);
- if (!dev)
+ priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+ orinoco_cs_hard_reset, NULL);
+ if (!priv)
return -ENOMEM;
- priv = netdev_priv(dev);
card = priv->card;
/* Link both structures together */
card->p_dev = link;
- link->priv = dev;
+ link->priv = priv;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt;
- link->irq.Instance = dev;
+ link->irq.Instance = priv;
/* General socket configuration defaults can go here. In this
* client, we assume very little, and rely on the CIS for
@@ -146,14 +144,14 @@ orinoco_cs_probe(struct pcmcia_device *link)
*/
static void orinoco_cs_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct orinoco_private *priv = link->priv;
if (link->dev_node)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
orinoco_cs_release(link);
- free_orinocodev(dev);
+ free_orinocodev(priv);
} /* orinoco_cs_detach */
/*
@@ -239,8 +237,7 @@ next_entry:
static int
orinoco_cs_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
hermes_t *hw = &priv->hw;
int last_fn, last_ret;
@@ -295,29 +292,27 @@ orinoco_cs_config(struct pcmcia_device *link)
pcmcia_request_configuration(link, &link->conf));
/* Ok, we have the configuration, prepare to register the netdev */
- dev->base_addr = link->io.BasePort1;
- dev->irq = link->irq.AssignedIRQ;
card->node.major = card->node.minor = 0;
- SET_NETDEV_DEV(dev, &handle_to_dev(link));
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, link->io.BasePort1,
+ link->irq.AssignedIRQ) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
/* At this point, the dev_node_t structure(s) needs to be
* initialized and arranged in a linked list at link->dev_node. */
- strcpy(card->node.dev_name, dev->name);
+ strcpy(card->node.dev_name, priv->ndev->name);
link->dev_node = &card->node; /* link->dev_node being non-NULL is also
* used to indicate that the
* net_device has been registered */
-
- /* Finally, report what we've done */
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
- link->irq.AssignedIRQ, link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
return 0;
cs_failed:
@@ -336,8 +331,7 @@ orinoco_cs_config(struct pcmcia_device *link)
static void
orinoco_cs_release(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
unsigned long flags;
/* We're committed to taking the device away now, so mark the
@@ -353,62 +347,26 @@ orinoco_cs_release(struct pcmcia_device *link)
static int orinoco_cs_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
- int err = 0;
- unsigned long flags;
/* This is probably racy, but I can't think of
a better way, short of rewriting the PCMCIA
layer to not suck :-( */
- if (!test_bit(0, &card->hard_reset_in_progress)) {
- spin_lock_irqsave(&priv->lock, flags);
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
-
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ if (!test_bit(0, &card->hard_reset_in_progress))
+ orinoco_down(priv);
return 0;
}
static int orinoco_cs_resume(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
int err = 0;
- unsigned long flags;
-
- if (!test_bit(0, &card->hard_reset_in_progress)) {
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
- netif_device_attach(dev);
- priv->hw_unavailable--;
-
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
- }
+ if (!test_bit(0, &card->hard_reset_in_progress))
+ err = orinoco_up(priv);
return err;
}
diff --git a/drivers/net/wireless/orinoco/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c
index b01726255c6..c13a4c38341 100644
--- a/drivers/net/wireless/orinoco/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco/orinoco_nortel.c
@@ -144,7 +144,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *bridge_io, *attr_io;
err = pci_enable_device(pdev);
@@ -181,24 +180,22 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_nortel_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_nortel_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -217,24 +214,28 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -256,17 +257,16 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
static void __devexit orinoco_nortel_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
/* Clear LEDs */
iowrite16(0, card->bridge_io + 10);
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index 78cafff1fb2..fea7781948e 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
@@ -116,7 +116,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io;
err = pci_enable_device(pdev);
@@ -139,22 +138,20 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_pci_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_pci_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -167,24 +164,28 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -200,13 +201,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h
index c655b4a3de1..ea7231af40a 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco/orinoco_pci.h
@@ -21,30 +21,10 @@ struct orinoco_pci_card {
#ifdef CONFIG_PM
static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- err = orinoco_lock(priv, &flags);
- if (err) {
- printk(KERN_ERR "%s: cannot lock hardware for suspend\n",
- dev->name);
- return err;
- }
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: error %d bringing interface down "
- "for suspend\n", dev->name, err);
-
- netif_device_detach(dev);
-
- priv->hw_unavailable++;
-
- orinoco_unlock(priv, &flags);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
- free_irq(pdev->irq, dev);
+ orinoco_down(priv);
+ free_irq(pdev->irq, priv);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -54,9 +34,8 @@ static int orinoco_pci_suspend(struct pci_dev *pdev, pm_message_t state)
static int orinoco_pci_resume(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
+ struct net_device *dev = priv->ndev;
int err;
pci_set_power_state(pdev, 0);
@@ -69,7 +48,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ dev->name, priv);
if (err) {
printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
dev->name);
@@ -77,29 +56,9 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
return -EBUSY;
}
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: error %d re-initializing firmware "
- "on resume\n", dev->name, err);
- return err;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
+ err = orinoco_up(priv);
- priv->hw_unavailable--;
-
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card on resume\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return err;
}
#else
#define orinoco_pci_suspend NULL
diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index a2a4471c033..3f2942a1e4f 100644
--- a/drivers/net/wireless/orinoco/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
@@ -183,7 +183,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *attr_io, *bridge_io;
err = pci_enable_device(pdev);
@@ -220,24 +219,22 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_plx_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_plx_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
card->attr_io = attr_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -256,24 +253,28 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -295,14 +296,13 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->attr_io);
pci_iounmap(pdev, card->bridge_io);
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index cda0e6e4d7a..d3452548cc7 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -94,7 +94,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
int err;
struct orinoco_private *priv;
struct orinoco_pci_card *card;
- struct net_device *dev;
void __iomem *hermes_io, *bridge_io;
err = pci_enable_device(pdev);
@@ -124,23 +123,21 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
}
/* Allocate network device */
- dev = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_tmd_cor_reset, NULL);
- if (!dev) {
+ priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
+ orinoco_tmd_cor_reset, NULL);
+ if (!priv) {
printk(KERN_ERR PFX "Cannot allocate network device\n");
err = -ENOMEM;
goto fail_alloc;
}
- priv = netdev_priv(dev);
card = priv->card;
card->bridge_io = bridge_io;
- SET_NETDEV_DEV(dev, &pdev->dev);
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, dev);
+ DRIVER_NAME, priv);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
err = -EBUSY;
@@ -153,24 +150,28 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
goto fail;
}
- err = register_netdev(dev);
+ err = orinoco_init(priv);
if (err) {
- printk(KERN_ERR PFX "Cannot register network device\n");
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
goto fail;
}
- pci_set_drvdata(pdev, dev);
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name,
- pci_name(pdev));
+ err = orinoco_if_add(priv, 0, 0);
+ if (err) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
+ goto fail;
+ }
+
+ pci_set_drvdata(pdev, priv);
return 0;
fail:
- free_irq(pdev->irq, dev);
+ free_irq(pdev->irq, priv);
fail_irq:
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
fail_alloc:
pci_iounmap(pdev, hermes_io);
@@ -189,14 +190,13 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = pci_get_drvdata(pdev);
struct orinoco_pci_card *card = priv->card;
- unregister_netdev(dev);
- free_irq(pdev->irq, dev);
+ orinoco_if_del(priv);
+ free_irq(pdev->irq, priv);
pci_set_drvdata(pdev, NULL);
- free_orinocodev(dev);
+ free_orinocodev(priv);
pci_iounmap(pdev, priv->hw.iobase);
pci_iounmap(pdev, card->bridge_io);
pci_release_regions(pdev);
diff --git a/drivers/net/wireless/orinoco/scan.c b/drivers/net/wireless/orinoco/scan.c
index 89d699d4dfe..d2f10e9c216 100644
--- a/drivers/net/wireless/orinoco/scan.c
+++ b/drivers/net/wireless/orinoco/scan.c
@@ -5,147 +5,166 @@
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/etherdevice.h>
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
#include "hermes.h"
#include "orinoco.h"
+#include "main.h"
#include "scan.h"
-#define ORINOCO_MAX_BSS_COUNT 64
+#define ZERO_DBM_OFFSET 0x95
+#define MAX_SIGNAL_LEVEL 0x8A
+#define MIN_SIGNAL_LEVEL 0x2F
-#define PRIV_BSS ((struct bss_element *)priv->bss_xbss_data)
-#define PRIV_XBSS ((struct xbss_element *)priv->bss_xbss_data)
+#define SIGNAL_TO_DBM(x) \
+ (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \
+ - ZERO_DBM_OFFSET)
+#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100)
-int orinoco_bss_data_allocate(struct orinoco_private *priv)
+static int symbol_build_supp_rates(u8 *buf, const __le16 *rates)
{
- if (priv->bss_xbss_data)
- return 0;
-
- if (priv->has_ext_scan)
- priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
- sizeof(struct xbss_element),
- GFP_KERNEL);
- else
- priv->bss_xbss_data = kzalloc(ORINOCO_MAX_BSS_COUNT *
- sizeof(struct bss_element),
- GFP_KERNEL);
-
- if (!priv->bss_xbss_data) {
- printk(KERN_WARNING "Out of memory allocating beacons");
- return -ENOMEM;
+ int i;
+ u8 rate;
+
+ buf[0] = WLAN_EID_SUPP_RATES;
+ for (i = 0; i < 5; i++) {
+ rate = le16_to_cpu(rates[i]);
+ /* NULL terminated */
+ if (rate == 0x0)
+ break;
+ buf[i + 2] = rate;
}
- return 0;
-}
+ buf[1] = i;
-void orinoco_bss_data_free(struct orinoco_private *priv)
-{
- kfree(priv->bss_xbss_data);
- priv->bss_xbss_data = NULL;
+ return i + 2;
}
-void orinoco_bss_data_init(struct orinoco_private *priv)
+static int prism_build_supp_rates(u8 *buf, const u8 *rates)
{
int i;
- INIT_LIST_HEAD(&priv->bss_free_list);
- INIT_LIST_HEAD(&priv->bss_list);
- if (priv->has_ext_scan)
- for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
- list_add_tail(&(PRIV_XBSS[i].list),
- &priv->bss_free_list);
- else
- for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++)
- list_add_tail(&(PRIV_BSS[i].list),
- &priv->bss_free_list);
-
-}
-
-void orinoco_clear_scan_results(struct orinoco_private *priv,
- unsigned long scan_age)
-{
- if (priv->has_ext_scan) {
- struct xbss_element *bss;
- struct xbss_element *tmp_bss;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
- if (!scan_age ||
- time_after(jiffies, bss->last_scanned + scan_age)) {
- list_move_tail(&bss->list,
- &priv->bss_free_list);
- /* Don't blow away ->list, just BSS data */
- memset(&bss->bss, 0, sizeof(bss->bss));
- bss->last_scanned = 0;
- }
- }
- } else {
- struct bss_element *bss;
- struct bss_element *tmp_bss;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) {
- if (!scan_age ||
- time_after(jiffies, bss->last_scanned + scan_age)) {
- list_move_tail(&bss->list,
- &priv->bss_free_list);
- /* Don't blow away ->list, just BSS data */
- memset(&bss->bss, 0, sizeof(bss->bss));
- bss->last_scanned = 0;
- }
+ buf[0] = WLAN_EID_SUPP_RATES;
+ for (i = 0; i < 8; i++) {
+ /* NULL terminated */
+ if (rates[i] == 0x0)
+ break;
+ buf[i + 2] = rates[i];
+ }
+ buf[1] = i;
+
+ /* We might still have another 2 rates, which need to go in
+ * extended supported rates */
+ if (i == 8 && rates[i] > 0) {
+ buf[10] = WLAN_EID_EXT_SUPP_RATES;
+ for (; i < 10; i++) {
+ /* NULL terminated */
+ if (rates[i] == 0x0)
+ break;
+ buf[i + 2] = rates[i];
}
+ buf[11] = i - 8;
}
+
+ return (i < 8) ? i + 2 : i + 4;
}
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom)
+static void orinoco_add_hostscan_result(struct orinoco_private *priv,
+ const union hermes_scan_info *bss)
{
- struct xbss_element *bss = NULL;
- int found = 0;
-
- /* Try to update an existing bss first */
- list_for_each_entry(bss, &priv->bss_list, list) {
- if (compare_ether_addr(bss->bss.bssid, atom->bssid))
- continue;
- /* ESSID lengths */
- if (bss->bss.data[1] != atom->data[1])
- continue;
- if (memcmp(&bss->bss.data[2], &atom->data[2],
- atom->data[1]))
- continue;
- found = 1;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u8 ie_buf[46];
+ u64 timestamp;
+ s32 signal;
+ u16 capability;
+ u16 beacon_interval;
+ int ie_len;
+ int freq;
+ int len;
+
+ len = le16_to_cpu(bss->a.essid_len);
+
+ /* Reconstruct SSID and bitrate IEs to pass up */
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = len;
+ memcpy(&ie_buf[2], bss->a.essid, len);
+
+ ie = ie_buf + len + 2;
+ ie_len = ie_buf[1] + 2;
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ ie_len += symbol_build_supp_rates(ie, bss->s.rates);
break;
- }
- /* Grab a bss off the free list */
- if (!found && !list_empty(&priv->bss_free_list)) {
- bss = list_entry(priv->bss_free_list.next,
- struct xbss_element, list);
- list_del(priv->bss_free_list.next);
+ case FIRMWARE_TYPE_INTERSIL:
+ ie_len += prism_build_supp_rates(ie, bss->p.rates);
+ break;
- list_add_tail(&bss->list, &priv->bss_list);
+ case FIRMWARE_TYPE_AGERE:
+ default:
+ break;
}
- if (bss) {
- /* Always update the BSS to get latest beacon info */
- memcpy(&bss->bss, atom, sizeof(bss->bss));
- bss->last_scanned = jiffies;
- }
+ freq = ieee80211_dsss_chan_to_freq(le16_to_cpu(bss->a.channel));
+ channel = ieee80211_get_channel(wiphy, freq);
+ timestamp = 0;
+ capability = le16_to_cpu(bss->a.capabilities);
+ beacon_interval = le16_to_cpu(bss->a.beacon_interv);
+ signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
+
+ cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
+ capability, beacon_interval, ie_buf, ie_len,
+ signal, GFP_KERNEL);
}
-int orinoco_process_scan_results(struct orinoco_private *priv,
- unsigned char *buf,
- int len)
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+ struct agere_ext_scan_info *bss,
+ size_t len)
{
- int offset; /* In the scan data */
- union hermes_scan_info *atom;
- int atom_len;
+ struct wiphy *wiphy = priv_to_wiphy(priv);
+ struct ieee80211_channel *channel;
+ u8 *ie;
+ u64 timestamp;
+ s32 signal;
+ u16 capability;
+ u16 beacon_interval;
+ size_t ie_len;
+ int chan, freq;
+
+ ie_len = len - sizeof(*bss);
+ ie = orinoco_get_ie(bss->data, ie_len, WLAN_EID_DS_PARAMS);
+ chan = ie ? ie[2] : 0;
+ freq = ieee80211_dsss_chan_to_freq(chan);
+ channel = ieee80211_get_channel(wiphy, freq);
+
+ timestamp = le64_to_cpu(bss->timestamp);
+ capability = le16_to_cpu(bss->capabilities);
+ beacon_interval = le16_to_cpu(bss->beacon_interval);
+ ie = bss->data;
+ signal = SIGNAL_TO_MBM(bss->level);
+
+ cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
+ capability, beacon_interval, ie, ie_len,
+ signal, GFP_KERNEL);
+}
+
+void orinoco_add_hostscan_results(struct orinoco_private *priv,
+ unsigned char *buf,
+ size_t len)
+{
+ int offset; /* In the scan data */
+ size_t atom_len;
+ bool abort = false;
switch (priv->firmware_type) {
case FIRMWARE_TYPE_AGERE:
atom_len = sizeof(struct agere_scan_apinfo);
offset = 0;
break;
+
case FIRMWARE_TYPE_SYMBOL:
/* Lack of documentation necessitates this hack.
* Different firmwares have 68 or 76 byte long atoms.
@@ -163,6 +182,7 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
atom_len = 68;
offset = 0;
break;
+
case FIRMWARE_TYPE_INTERSIL:
offset = 4;
if (priv->has_hostscan) {
@@ -170,64 +190,41 @@ int orinoco_process_scan_results(struct orinoco_private *priv,
/* Sanity check for atom_len */
if (atom_len < sizeof(struct prism2_scan_apinfo)) {
printk(KERN_ERR "%s: Invalid atom_len in scan "
- "data: %d\n", priv->ndev->name,
+ "data: %zu\n", priv->ndev->name,
atom_len);
- return -EIO;
+ abort = true;
+ goto scan_abort;
}
} else
atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
+
default:
- return -EOPNOTSUPP;
+ abort = true;
+ goto scan_abort;
}
/* Check that we got an whole number of atoms */
if ((len - offset) % atom_len) {
- printk(KERN_ERR "%s: Unexpected scan data length %d, "
- "atom_len %d, offset %d\n", priv->ndev->name, len,
+ printk(KERN_ERR "%s: Unexpected scan data length %zu, "
+ "atom_len %zu, offset %d\n", priv->ndev->name, len,
atom_len, offset);
- return -EIO;
+ abort = true;
+ goto scan_abort;
}
- orinoco_clear_scan_results(priv, msecs_to_jiffies(15000));
-
- /* Read the entries one by one */
+ /* Process the entries one by one */
for (; offset + atom_len <= len; offset += atom_len) {
- int found = 0;
- struct bss_element *bss = NULL;
+ union hermes_scan_info *atom;
- /* Get next atom */
atom = (union hermes_scan_info *) (buf + offset);
- /* Try to update an existing bss first */
- list_for_each_entry(bss, &priv->bss_list, list) {
- if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid))
- continue;
- if (le16_to_cpu(bss->bss.a.essid_len) !=
- le16_to_cpu(atom->a.essid_len))
- continue;
- if (memcmp(bss->bss.a.essid, atom->a.essid,
- le16_to_cpu(atom->a.essid_len)))
- continue;
- found = 1;
- break;
- }
-
- /* Grab a bss off the free list */
- if (!found && !list_empty(&priv->bss_free_list)) {
- bss = list_entry(priv->bss_free_list.next,
- struct bss_element, list);
- list_del(priv->bss_free_list.next);
-
- list_add_tail(&bss->list, &priv->bss_list);
- }
-
- if (bss) {
- /* Always update the BSS to get latest beacon info */
- memcpy(&bss->bss, atom, sizeof(bss->bss));
- bss->last_scanned = jiffies;
- }
+ orinoco_add_hostscan_result(priv, atom);
}
- return 0;
+ scan_abort:
+ if (priv->scan_request) {
+ cfg80211_scan_done(priv->scan_request, abort);
+ priv->scan_request = NULL;
+ }
}
diff --git a/drivers/net/wireless/orinoco/scan.h b/drivers/net/wireless/orinoco/scan.h
index f319f7466af..2dc4e046dbd 100644
--- a/drivers/net/wireless/orinoco/scan.h
+++ b/drivers/net/wireless/orinoco/scan.h
@@ -9,21 +9,12 @@
struct orinoco_private;
struct agere_ext_scan_info;
-/* Setup and free memory for scan results */
-int orinoco_bss_data_allocate(struct orinoco_private *priv);
-void orinoco_bss_data_free(struct orinoco_private *priv);
-void orinoco_bss_data_init(struct orinoco_private *priv);
-
/* Add scan results */
-void orinoco_add_ext_scan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom);
-int orinoco_process_scan_results(struct orinoco_private *dev,
- unsigned char *buf,
- int len);
-
-/* Clear scan results */
-void orinoco_clear_scan_results(struct orinoco_private *priv,
- unsigned long scan_age);
-
+void orinoco_add_extscan_result(struct orinoco_private *priv,
+ struct agere_ext_scan_info *atom,
+ size_t len);
+void orinoco_add_hostscan_results(struct orinoco_private *dev,
+ unsigned char *buf,
+ size_t len);
#endif /* _ORINOCO_SCAN_H_ */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index 38e5198e44c..c361310b885 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -178,27 +178,25 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
static int
spectrum_cs_probe(struct pcmcia_device *link)
{
- struct net_device *dev;
struct orinoco_private *priv;
struct orinoco_pccard *card;
- dev = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
- spectrum_cs_hard_reset,
- spectrum_cs_stop_firmware);
- if (!dev)
+ priv = alloc_orinocodev(sizeof(*card), &handle_to_dev(link),
+ spectrum_cs_hard_reset,
+ spectrum_cs_stop_firmware);
+ if (!priv)
return -ENOMEM;
- priv = netdev_priv(dev);
card = priv->card;
/* Link both structures together */
card->p_dev = link;
- link->priv = dev;
+ link->priv = priv;
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = orinoco_interrupt;
- link->irq.Instance = dev;
+ link->irq.Instance = priv;
/* General socket configuration defaults can go here. In this
* client, we assume very little, and rely on the CIS for
@@ -219,14 +217,14 @@ spectrum_cs_probe(struct pcmcia_device *link)
*/
static void spectrum_cs_detach(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
+ struct orinoco_private *priv = link->priv;
if (link->dev_node)
- unregister_netdev(dev);
+ orinoco_if_del(priv);
spectrum_cs_release(link);
- free_orinocodev(dev);
+ free_orinocodev(priv);
} /* spectrum_cs_detach */
/*
@@ -306,8 +304,7 @@ next_entry:
static int
spectrum_cs_config(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
struct orinoco_pccard *card = priv->card;
hermes_t *hw = &priv->hw;
int last_fn, last_ret;
@@ -362,34 +359,31 @@ spectrum_cs_config(struct pcmcia_device *link)
pcmcia_request_configuration(link, &link->conf));
/* Ok, we have the configuration, prepare to register the netdev */
- dev->base_addr = link->io.BasePort1;
- dev->irq = link->irq.AssignedIRQ;
card->node.major = card->node.minor = 0;
/* Reset card */
if (spectrum_cs_hard_reset(priv) != 0)
goto failed;
- SET_NETDEV_DEV(dev, &handle_to_dev(link));
- /* Tell the stack we exist */
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR PFX "register_netdev() failed\n");
+ /* Initialise the main driver */
+ if (orinoco_init(priv) != 0) {
+ printk(KERN_ERR PFX "orinoco_init() failed\n");
+ goto failed;
+ }
+
+ /* Register an interface with the stack */
+ if (orinoco_if_add(priv, link->io.BasePort1,
+ link->irq.AssignedIRQ) != 0) {
+ printk(KERN_ERR PFX "orinoco_if_add() failed\n");
goto failed;
}
/* At this point, the dev_node_t structure(s) needs to be
* initialized and arranged in a linked list at link->dev_node. */
- strcpy(card->node.dev_name, dev->name);
+ strcpy(card->node.dev_name, priv->ndev->name);
link->dev_node = &card->node; /* link->dev_node being non-NULL is also
* used to indicate that the
* net_device has been registered */
-
- /* Finally, report what we've done */
- printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
- "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent),
- link->irq.AssignedIRQ, link->io.BasePort1,
- link->io.BasePort1 + link->io.NumPorts1 - 1);
-
return 0;
cs_failed:
@@ -408,8 +402,7 @@ spectrum_cs_config(struct pcmcia_device *link)
static void
spectrum_cs_release(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = link->priv;
unsigned long flags;
/* We're committed to taking the device away now, so mark the
@@ -427,23 +420,11 @@ spectrum_cs_release(struct pcmcia_device *link)
static int
spectrum_cs_suspend(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
+ struct orinoco_private *priv = link->priv;
int err = 0;
/* Mark the device as stopped, to block IO until later */
- spin_lock_irqsave(&priv->lock, flags);
-
- err = __orinoco_down(dev);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
-
- spin_unlock_irqrestore(&priv->lock, flags);
+ orinoco_down(priv);
return err;
}
@@ -451,33 +432,10 @@ spectrum_cs_suspend(struct pcmcia_device *link)
static int
spectrum_cs_resume(struct pcmcia_device *link)
{
- struct net_device *dev = link->priv;
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
- int err;
-
- err = orinoco_reinit_firmware(dev);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- return -EIO;
- }
-
- spin_lock_irqsave(&priv->lock, flags);
-
- netif_device_attach(dev);
- priv->hw_unavailable--;
+ struct orinoco_private *priv = link->priv;
+ int err = orinoco_up(priv);
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(dev);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
+ return err;
}
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 3f081423439..b6ff3dbb7dd 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -7,6 +7,7 @@
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>
#include "hermes.h"
#include "hermes_rid.h"
@@ -23,7 +24,7 @@
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_statistics *wstats = &priv->wstats;
int err;
@@ -51,7 +52,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
* here so we're not safe to sleep here. */
hermes_inquire(hw, HERMES_INQ_TALLIES);
- if (priv->iw_mode == IW_MODE_ADHOC) {
+ if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
memset(&wstats->qual, 0, sizeof(wstats->qual));
/* If a spy address is defined, we report stats of the
* first spy address - Jean II */
@@ -87,31 +88,12 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
/* Wireless extensions */
/********************************************************************/
-static int orinoco_ioctl_getname(struct net_device *dev,
- struct iw_request_info *info,
- char *name,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int numrates;
- int err;
-
- err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
-
- if (!err && (numrates > 2))
- strcpy(name, "IEEE 802.11b");
- else
- strcpy(name, "IEEE 802.11-DS");
-
- return 0;
-}
-
static int orinoco_ioctl_setwap(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *ap_addr,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -142,7 +124,7 @@ static int orinoco_ioctl_setwap(struct net_device *dev,
goto out;
}
- if (priv->iw_mode != IW_MODE_INFRA) {
+ if (priv->iw_mode != NL80211_IFTYPE_STATION) {
printk(KERN_WARNING "%s: Manual roaming supported only in "
"managed mode\n", dev->name);
err = -EOPNOTSUPP;
@@ -172,7 +154,7 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
struct sockaddr *ap_addr,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
@@ -190,184 +172,12 @@ static int orinoco_ioctl_getwap(struct net_device *dev,
return err;
}
-static int orinoco_ioctl_setmode(struct net_device *dev,
- struct iw_request_info *info,
- u32 *mode,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (priv->iw_mode == *mode)
- return 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (*mode) {
- case IW_MODE_ADHOC:
- if (!priv->has_ibss && !priv->has_port3)
- err = -EOPNOTSUPP;
- break;
-
- case IW_MODE_INFRA:
- break;
-
- case IW_MODE_MONITOR:
- if (priv->broken_monitor && !force_monitor) {
- printk(KERN_WARNING "%s: Monitor mode support is "
- "buggy in this firmware, not enabling\n",
- dev->name);
- err = -EOPNOTSUPP;
- }
- break;
-
- default:
- err = -EOPNOTSUPP;
- break;
- }
-
- if (err == -EINPROGRESS) {
- priv->iw_mode = *mode;
- set_port_type(priv);
- }
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getmode(struct net_device *dev,
- struct iw_request_info *info,
- u32 *mode,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
-
- *mode = priv->iw_mode;
- return 0;
-}
-
-static int orinoco_ioctl_getiwrange(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *rrq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- struct iw_range *range = (struct iw_range *) extra;
- int numrates;
- int i, k;
-
- rrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
-
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 22;
-
- /* Set available channels/frequencies */
- range->num_channels = NUM_CHANNELS;
- k = 0;
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (priv->channel_mask & (1 << i)) {
- range->freq[k].i = i + 1;
- range->freq[k].m = (ieee80211_dsss_chan_to_freq(i + 1) *
- 100000);
- range->freq[k].e = 1;
- k++;
- }
-
- if (k >= IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = k;
- range->sensitivity = 3;
-
- if (priv->has_wep) {
- range->max_encoding_tokens = ORINOCO_MAX_KEYS;
- range->encoding_size[0] = SMALL_KEY_SIZE;
- range->num_encoding_sizes = 1;
-
- if (priv->has_big_wep) {
- range->encoding_size[1] = LARGE_KEY_SIZE;
- range->num_encoding_sizes = 2;
- }
- }
-
- if (priv->has_wpa)
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_CIPHER_TKIP;
-
- if ((priv->iw_mode == IW_MODE_ADHOC) && (!SPY_NUMBER(priv))) {
- /* Quality stats meaningless in ad-hoc mode */
- } else {
- range->max_qual.qual = 0x8b - 0x2f;
- range->max_qual.level = 0x2f - 0x95 - 1;
- range->max_qual.noise = 0x2f - 0x95 - 1;
- /* Need to get better values */
- range->avg_qual.qual = 0x24;
- range->avg_qual.level = 0xC2;
- range->avg_qual.noise = 0x9E;
- }
-
- err = orinoco_hw_get_bitratelist(priv, &numrates,
- range->bitrate, IW_MAX_BITRATES);
- if (err)
- return err;
- range->num_bitrates = numrates;
-
- /* Set an indication of the max TCP throughput in bit/s that we can
- * expect using this interface. May be use for QoS stuff...
- * Jean II */
- if (numrates > 2)
- range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
- else
- range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
-
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
-
- range->min_pmp = 0;
- range->max_pmp = 65535000;
- range->min_pmt = 0;
- range->max_pmt = 65535 * 1000; /* ??? */
- range->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_TIMEOUT;
- range->pm_capa = (IW_POWER_PERIOD | IW_POWER_TIMEOUT |
- IW_POWER_UNICAST_R);
-
- range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
- range->retry_flags = IW_RETRY_LIMIT;
- range->r_time_flags = IW_RETRY_LIFETIME;
- range->min_retry = 0;
- range->max_retry = 65535; /* ??? */
- range->min_r_time = 0;
- range->max_r_time = 65535 * 1000; /* ??? */
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
- range->scan_capa = IW_SCAN_CAPA_ESSID;
- else
- range->scan_capa = IW_SCAN_CAPA_NONE;
-
- /* Event capability (kernel) */
- IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
- /* Event capability (driver) */
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
- IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
-
- return 0;
-}
-
static int orinoco_ioctl_setiwencode(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *erq,
char *keybuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
int setindex = priv->tx_key;
int encode_alg = priv->encode_alg;
@@ -469,7 +279,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
struct iw_point *erq,
char *keybuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
u16 xlen = 0;
unsigned long flags;
@@ -508,7 +318,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev,
struct iw_point *erq,
char *essidbuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
@@ -539,7 +349,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
struct iw_point *erq,
char *essidbuf)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int active;
int err = 0;
unsigned long flags;
@@ -562,59 +372,18 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
return 0;
}
-static int orinoco_ioctl_setnick(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *nrq,
- char *nickbuf)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- if (nrq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, nickbuf, nrq->length);
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getnick(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *nrq,
- char *nickbuf)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE);
- orinoco_unlock(priv, &flags);
-
- nrq->length = strlen(priv->nick);
-
- return 0;
-}
-
static int orinoco_ioctl_setfreq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int chan = -1;
unsigned long flags;
int err = -EINPROGRESS; /* Call commit handler */
/* In infrastructure mode the AP sets the channel */
- if (priv->iw_mode == IW_MODE_INFRA)
+ if (priv->iw_mode == NL80211_IFTYPE_STATION)
return -EBUSY;
if ((frq->e == 0) && (frq->m <= 1000)) {
@@ -640,7 +409,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev,
return -EBUSY;
priv->channel = chan;
- if (priv->iw_mode == IW_MODE_MONITOR) {
+ if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
/* Fast channel change - no commit if successful */
hermes_t *hw = &priv->hw;
err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
@@ -657,7 +426,7 @@ static int orinoco_ioctl_getfreq(struct net_device *dev,
struct iw_freq *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int tmp;
/* Locking done in there */
@@ -676,7 +445,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev,
struct iw_param *srq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
u16 val;
int err;
@@ -705,7 +474,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev,
struct iw_param *srq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = srq->value;
unsigned long flags;
@@ -728,7 +497,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = rrq->value;
unsigned long flags;
@@ -752,7 +521,7 @@ static int orinoco_ioctl_getrts(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
rrq->value = priv->rts_thresh;
rrq->disabled = (rrq->value == 2347);
@@ -766,7 +535,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev,
struct iw_param *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -806,7 +575,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev,
struct iw_param *frq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err;
u16 val;
@@ -847,7 +616,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int ratemode;
int bitrate; /* 100s of kilobits */
unsigned long flags;
@@ -881,7 +650,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = 0;
int bitrate, automatic;
unsigned long flags;
@@ -910,7 +679,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev,
struct iw_param *prq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
@@ -964,7 +733,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev,
struct iw_param *prq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
u16 enable, period, timeout, mcast;
@@ -1018,7 +787,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, alg = ext->alg, set_key = 1;
@@ -1079,7 +848,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
case IW_ENCODE_ALG_TKIP:
{
- hermes_t *hw = &priv->hw;
u8 *tkip_iv = NULL;
if (!priv->has_wpa ||
@@ -1094,7 +862,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
tkip_iv = &ext->rx_seq[0];
- err = __orinoco_hw_set_tkip_key(hw, idx,
+ err = __orinoco_hw_set_tkip_key(priv, idx,
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
(u8 *) &priv->tkip_key[idx],
tkip_iv, NULL);
@@ -1120,7 +888,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
union iwreq_data *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_point *encoding = &wrqu->encoding;
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
int idx, max_key_len;
@@ -1177,7 +945,7 @@ static int orinoco_ioctl_set_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_param *param = &wrqu->param;
unsigned long flags;
@@ -1255,7 +1023,7 @@ static int orinoco_ioctl_get_auth(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
struct iw_param *param = &wrqu->param;
unsigned long flags;
int ret = 0;
@@ -1295,7 +1063,7 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
u8 *buf;
unsigned long flags;
@@ -1338,7 +1106,7 @@ static int orinoco_ioctl_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err = 0;
@@ -1367,7 +1135,7 @@ static int orinoco_ioctl_set_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
struct iw_mlme *mlme = (struct iw_mlme *)extra;
unsigned long flags;
@@ -1408,7 +1176,7 @@ static int orinoco_ioctl_getretry(struct net_device *dev,
struct iw_param *rrq,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int err = 0;
u16 short_limit, long_limit, lifetime;
@@ -1462,7 +1230,7 @@ static int orinoco_ioctl_reset(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -1487,7 +1255,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = *((int *) extra);
unsigned long flags;
@@ -1508,7 +1276,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
*val = priv->ibss_port;
@@ -1520,7 +1288,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int val = *((int *) extra);
int err = 0;
unsigned long flags;
@@ -1566,7 +1334,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
*val = priv->prefer_port3;
@@ -1578,7 +1346,7 @@ static int orinoco_ioctl_setpreamble(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int val;
@@ -1610,7 +1378,7 @@ static int orinoco_ioctl_getpreamble(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
int *val = (int *) extra;
if (!priv->has_preamble)
@@ -1630,7 +1398,7 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
struct iw_point *data,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
+ struct orinoco_private *priv = ndev_priv(dev);
hermes_t *hw = &priv->hw;
int rid = data->flags;
u16 length;
@@ -1661,519 +1429,6 @@ static int orinoco_ioctl_getrid(struct net_device *dev,
return err;
}
-/* Trigger a scan (look for other cells in the vicinity) */
-static int orinoco_ioctl_setscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *srq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- hermes_t *hw = &priv->hw;
- struct iw_scan_req *si = (struct iw_scan_req *) extra;
- int err = 0;
- unsigned long flags;
-
- /* Note : you may have realised that, as this is a SET operation,
- * this is privileged and therefore a normal user can't
- * perform scanning.
- * This is not an error, while the device perform scanning,
- * traffic doesn't flow, so it's a perfect DoS...
- * Jean II */
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Scanning with port 0 disabled would fail */
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- /* In monitor mode, the scan results are always empty.
- * Probe responses are passed to the driver as received
- * frames and could be processed in software. */
- if (priv->iw_mode == IW_MODE_MONITOR) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Note : because we don't lock out the irq handler, the way
- * we access scan variables in priv is critical.
- * o scan_inprogress : not touched by irq handler
- * o scan_mode : not touched by irq handler
- * Before modifying anything on those variables, please think hard !
- * Jean II */
-
- /* Save flags */
- priv->scan_mode = srq->flags;
-
- /* Always trigger scanning, even if it's in progress.
- * This way, if the info frame get lost, we will recover somewhat
- * gracefully - Jean II */
-
- if (priv->has_hostscan) {
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_SYMBOL:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN_SYMBOL,
- HERMES_HOSTSCAN_SYMBOL_ONCE |
- HERMES_HOSTSCAN_SYMBOL_BCAST);
- break;
- case FIRMWARE_TYPE_INTERSIL: {
- __le16 req[3];
-
- req[0] = cpu_to_le16(0x3fff); /* All channels */
- req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
- req[2] = 0; /* Any ESSID */
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN, &req);
- }
- break;
- case FIRMWARE_TYPE_AGERE:
- if (priv->scan_mode & IW_SCAN_THIS_ESSID) {
- struct hermes_idstring idbuf;
- size_t len = min(sizeof(idbuf.val),
- (size_t) si->essid_len);
- idbuf.len = cpu_to_le16(len);
- memcpy(idbuf.val, si->essid, len);
-
- err = hermes_write_ltv(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- HERMES_BYTES_TO_RECLEN(len + 2),
- &idbuf);
- } else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- 0); /* Any ESSID */
- if (err)
- break;
-
- if (priv->has_ext_scan) {
- /* Clear scan results at the start of
- * an extended scan */
- orinoco_clear_scan_results(priv,
- msecs_to_jiffies(15000));
-
- /* TODO: Is this available on older firmware?
- * Can we use it to scan specific channels
- * for IW_SCAN_THIS_FREQ? */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANCHANNELS2GHZ,
- 0x7FFF);
- if (err)
- goto out;
-
- err = hermes_inquire(hw,
- HERMES_INQ_CHANNELINFO);
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
- break;
- }
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
- /* One more client */
- if (!err)
- priv->scan_inprogress = 1;
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-#define MAX_CUSTOM_LEN 64
-
-/* Translate scan data returned from the card to a card independant
- * format that the Wireless Tools will understand - Jean II */
-static inline char *orinoco_translate_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- union hermes_scan_info *bss,
- unsigned long last_scanned)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- u16 capabilities;
- u16 channel;
- struct iw_event iwe; /* Temporary buffer */
- char custom[MAX_CUSTOM_LEN];
-
- memset(&iwe, 0, sizeof(iwe));
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- iwe.u.data.length = le16_to_cpu(bss->a.essid_len);
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->a.essid);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- capabilities = le16_to_cpu(bss->a.capabilities);
- if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- channel = bss->s.channel;
- if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
- /* Add channel and frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- /* Add quality statistics. level and noise in dB. No link quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
- iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95;
- iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95;
- /* Wireless tools prior to 27.pre22 will show link quality
- * anyway, so we provide a reasonable value. */
- if (iwe.u.qual.level > iwe.u.qual.noise)
- iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
- else
- iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, NULL);
-
- /* Bit rate is not available in Lucent/Agere firmwares */
- if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
- char *current_val = current_ev + iwe_stream_lcp_len(info);
- int i;
- int step;
-
- if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
- step = 2;
- else
- step = 1;
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
- /* Max 10 values */
- for (i = 0; i < 10; i += step) {
- /* NULL terminated */
- if (bss->p.rates[i] == 0x0)
- break;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value =
- ((bss->p.rates[i] & 0x7f) * 500000);
- current_val = iwe_stream_add_value(info, current_ev,
- current_val,
- end_buf, &iwe,
- IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - current_ev) > iwe_stream_lcp_len(info))
- current_ev = current_val;
- }
-
- /* Beacon interval */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "bcn_int=%d",
- le16_to_cpu(bss->a.beacon_interv));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Capabilites */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "capab=0x%04x",
- capabilities);
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - last_scanned));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- return current_ev;
-}
-
-static inline char *orinoco_translate_ext_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- struct agere_ext_scan_info *bss,
- unsigned long last_scanned)
-{
- u16 capabilities;
- u16 channel;
- struct iw_event iwe; /* Temporary buffer */
- char custom[MAX_CUSTOM_LEN];
- u8 *ie;
-
- memset(&iwe, 0, sizeof(iwe));
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- ie = bss->data;
- iwe.u.data.length = ie[1];
- if (iwe.u.data.length) {
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, &ie[2]);
- }
-
- /* Add mode */
- capabilities = le16_to_cpu(bss->capabilities);
- if (capabilities & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- iwe.cmd = SIOCGIWMODE;
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS);
- channel = ie ? ie[2] : 0;
- if ((channel >= 1) && (channel <= NUM_CHANNELS)) {
- /* Add channel and frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = channel;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.u.freq.m = ieee80211_dsss_chan_to_freq(channel) * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- /* Add quality statistics. level and noise in dB. No link quality */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_DBM | IW_QUAL_QUAL_INVALID;
- iwe.u.qual.level = bss->level - 0x95;
- iwe.u.qual.noise = bss->noise - 0x95;
- /* Wireless tools prior to 27.pre22 will show link quality
- * anyway, so we provide a reasonable value. */
- if (iwe.u.qual.level > iwe.u.qual.noise)
- iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
- else
- iwe.u.qual.qual = 0;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, NULL);
-
- /* WPA IE */
- ie = orinoco_get_wpa_ie(bss->data, sizeof(bss->data));
- if (ie) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = ie[1] + 2;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ie);
- }
-
- /* RSN IE */
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN);
- if (ie) {
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = ie[1] + 2;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ie);
- }
-
- ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES);
- if (ie) {
- char *p = current_ev + iwe_stream_lcp_len(info);
- int i;
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
- for (i = 2; i < (ie[1] + 2); i++) {
- iwe.u.bitrate.value = ((ie[i] & 0x7F) * 500000);
- p = iwe_stream_add_value(info, current_ev, p, end_buf,
- &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if (p > (current_ev + iwe_stream_lcp_len(info)))
- current_ev = p;
- }
-
- /* Timestamp */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length =
- snprintf(custom, MAX_CUSTOM_LEN, "tsf=%016llx",
- (unsigned long long) le64_to_cpu(bss->timestamp));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Beacon interval */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "bcn_int=%d",
- le16_to_cpu(bss->beacon_interval));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Capabilites */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- "capab=0x%04x",
- capabilities);
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = snprintf(custom, MAX_CUSTOM_LEN,
- " Last beacon: %dms ago",
- jiffies_to_msecs(jiffies - last_scanned));
- if (iwe.u.data.length)
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, custom);
-
- return current_ev;
-}
-
-/* Return results of a scan */
-static int orinoco_ioctl_getscan(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *srq,
- char *extra)
-{
- struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- unsigned long flags;
- char *current_ev = extra;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (priv->scan_inprogress) {
- /* Important note : we don't want to block the caller
- * until results are ready for various reasons.
- * First, managing wait queues is complex and racy.
- * Second, we grab some rtnetlink lock before comming
- * here (in dev_ioctl()).
- * Third, we generate an Wireless Event, so the
- * caller can wait itself on that - Jean II */
- err = -EAGAIN;
- goto out;
- }
-
- if (priv->has_ext_scan) {
- struct xbss_element *bss;
-
- list_for_each_entry(bss, &priv->bss_list, list) {
- /* Translate this entry to WE format */
- current_ev =
- orinoco_translate_ext_scan(dev, info,
- current_ev,
- extra + srq->length,
- &bss->bss,
- bss->last_scanned);
-
- /* Check if there is space for one more entry */
- if ((extra + srq->length - current_ev)
- <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a
- * bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
-
- } else {
- struct bss_element *bss;
-
- list_for_each_entry(bss, &priv->bss_list, list) {
- /* Translate this entry to WE format */
- current_ev = orinoco_translate_scan(dev, info,
- current_ev,
- extra + srq->length,
- &bss->bss,
- bss->last_scanned);
-
- /* Check if there is space for one more entry */
- if ((extra + srq->length - current_ev)
- <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a
- * bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
- }
-
- srq->length = (current_ev - extra);
- srq->flags = (__u16) priv->scan_mode;
-
-out:
- orinoco_unlock(priv, &flags);
- return err;
-}
/* Commit handler, called after set operations */
static int orinoco_ioctl_commit(struct net_device *dev,
@@ -2181,50 +1436,17 @@ static int orinoco_ioctl_commit(struct net_device *dev,
void *wrqu,
char *extra)
{
- struct orinoco_private *priv = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
+ struct orinoco_private *priv = ndev_priv(dev);
unsigned long flags;
int err = 0;
if (!priv->open)
return 0;
- if (priv->broken_disableport) {
- orinoco_reset(&priv->reset_work);
- return 0;
- }
-
if (orinoco_lock(priv, &flags) != 0)
return err;
- err = hermes_disable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to disable port "
- "while reconfiguring card\n", dev->name);
- priv->broken_disableport = 1;
- goto out;
- }
-
- err = __orinoco_program_rids(dev);
- if (err) {
- printk(KERN_WARNING "%s: Unable to reconfigure card\n",
- dev->name);
- goto out;
- }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
- dev->name);
- goto out;
- }
-
- out:
- if (err) {
- printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
- schedule_work(&priv->reset_work);
- err = 0;
- }
+ err = orinoco_commit(priv);
orinoco_unlock(priv, &flags);
return err;
@@ -2258,26 +1480,24 @@ static const struct iw_priv_args orinoco_privtab[] = {
[IW_IOCTL_IDX(id)] = (iw_handler) func
static const iw_handler orinoco_handler[] = {
STD_IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit),
- STD_IW_HANDLER(SIOCGIWNAME, orinoco_ioctl_getname),
+ STD_IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
STD_IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq),
STD_IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq),
- STD_IW_HANDLER(SIOCSIWMODE, orinoco_ioctl_setmode),
- STD_IW_HANDLER(SIOCGIWMODE, orinoco_ioctl_getmode),
+ STD_IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode),
+ STD_IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode),
STD_IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens),
STD_IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens),
- STD_IW_HANDLER(SIOCGIWRANGE, orinoco_ioctl_getiwrange),
+ STD_IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange),
STD_IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
STD_IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
STD_IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
STD_IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
STD_IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap),
STD_IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap),
- STD_IW_HANDLER(SIOCSIWSCAN, orinoco_ioctl_setscan),
- STD_IW_HANDLER(SIOCGIWSCAN, orinoco_ioctl_getscan),
+ STD_IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan),
+ STD_IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan),
STD_IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid),
STD_IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid),
- STD_IW_HANDLER(SIOCSIWNICKN, orinoco_ioctl_setnick),
- STD_IW_HANDLER(SIOCGIWNICKN, orinoco_ioctl_getnick),
STD_IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate),
STD_IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate),
STD_IW_HANDLER(SIOCSIWRTS, orinoco_ioctl_setrts),
diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile
index c2050dee629..b542e68f178 100644
--- a/drivers/net/wireless/p54/Makefile
+++ b/drivers/net/wireless/p54/Makefile
@@ -1,3 +1,6 @@
+p54common-objs := eeprom.o fwio.o txrx.o main.o
+p54common-$(CONFIG_P54_LEDS) += led.o
+
obj-$(CONFIG_P54_COMMON) += p54common.o
obj-$(CONFIG_P54_USB) += p54usb.o
obj-$(CONFIG_P54_PCI) += p54pci.o
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
new file mode 100644
index 00000000000..0efe67deede
--- /dev/null
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -0,0 +1,753 @@
+/*
+ * EEPROM parser code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/sort.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+static struct ieee80211_rate p54_bgrates[] = {
+ { .bitrate = 10, .hw_value = 0, },
+ { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct ieee80211_rate p54_arates[] = {
+ { .bitrate = 60, .hw_value = 4, },
+ { .bitrate = 90, .hw_value = 5, },
+ { .bitrate = 120, .hw_value = 6, },
+ { .bitrate = 180, .hw_value = 7, },
+ { .bitrate = 240, .hw_value = 8, },
+ { .bitrate = 360, .hw_value = 9, },
+ { .bitrate = 480, .hw_value = 10, },
+ { .bitrate = 540, .hw_value = 11, },
+};
+
+#define CHAN_HAS_CAL BIT(0)
+#define CHAN_HAS_LIMIT BIT(1)
+#define CHAN_HAS_CURVE BIT(2)
+#define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
+
+struct p54_channel_entry {
+ u16 freq;
+ u16 data;
+ int index;
+ enum ieee80211_band band;
+};
+
+struct p54_channel_list {
+ struct p54_channel_entry *channels;
+ size_t entries;
+ size_t max_entries;
+ size_t band_channel_num[IEEE80211_NUM_BANDS];
+};
+
+static int p54_get_band_from_freq(u16 freq)
+{
+ /* FIXME: sync these values with the 802.11 spec */
+
+ if ((freq >= 2412) && (freq <= 2484))
+ return IEEE80211_BAND_2GHZ;
+
+ if ((freq >= 4920) && (freq <= 5825))
+ return IEEE80211_BAND_5GHZ;
+
+ return -1;
+}
+
+static int p54_compare_channels(const void *_a,
+ const void *_b)
+{
+ const struct p54_channel_entry *a = _a;
+ const struct p54_channel_entry *b = _b;
+
+ return a->index - b->index;
+}
+
+static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
+ struct ieee80211_supported_band *band_entry,
+ enum ieee80211_band band)
+{
+ /* TODO: generate rate array dynamically */
+
+ switch (band) {
+ case IEEE80211_BAND_2GHZ:
+ band_entry->bitrates = p54_bgrates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
+ break;
+ case IEEE80211_BAND_5GHZ:
+ band_entry->bitrates = p54_arates;
+ band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int p54_generate_band(struct ieee80211_hw *dev,
+ struct p54_channel_list *list,
+ enum ieee80211_band band)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_supported_band *tmp, *old;
+ unsigned int i, j;
+ int ret = -ENOMEM;
+
+ if ((!list->entries) || (!list->band_channel_num[band]))
+ return 0;
+
+ tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ goto err_out;
+
+ tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
+ list->band_channel_num[band], GFP_KERNEL);
+ if (!tmp->channels)
+ goto err_out;
+
+ ret = p54_fill_band_bitrates(dev, tmp, band);
+ if (ret)
+ goto err_out;
+
+ for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
+ (i < list->entries); i++) {
+
+ if (list->channels[i].band != band)
+ continue;
+
+ if (list->channels[i].data != CHAN_HAS_ALL) {
+ printk(KERN_ERR "%s:%s%s%s is/are missing for "
+ "channel:%d [%d MHz].\n",
+ wiphy_name(dev->wiphy),
+ (list->channels[i].data & CHAN_HAS_CAL ? "" :
+ " [iqauto calibration data]"),
+ (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
+ " [output power limits]"),
+ (list->channels[i].data & CHAN_HAS_CURVE ? "" :
+ " [curve data]"),
+ list->channels[i].index, list->channels[i].freq);
+ }
+
+ tmp->channels[j].band = list->channels[i].band;
+ tmp->channels[j].center_freq = list->channels[i].freq;
+ j++;
+ }
+
+ tmp->n_channels = list->band_channel_num[band];
+ old = priv->band_table[band];
+ priv->band_table[band] = tmp;
+ if (old) {
+ kfree(old->channels);
+ kfree(old);
+ }
+
+ return 0;
+
+err_out:
+ if (tmp) {
+ kfree(tmp->channels);
+ kfree(tmp);
+ }
+
+ return ret;
+}
+
+static void p54_update_channel_param(struct p54_channel_list *list,
+ u16 freq, u16 data)
+{
+ int band, i;
+
+ /*
+ * usually all lists in the eeprom are mostly sorted.
+ * so it's very likely that the entry we are looking for
+ * is right at the end of the list
+ */
+ for (i = list->entries; i >= 0; i--) {
+ if (freq == list->channels[i].freq) {
+ list->channels[i].data |= data;
+ break;
+ }
+ }
+
+ if ((i < 0) && (list->entries < list->max_entries)) {
+ /* entry does not exist yet. Initialize a new one. */
+ band = p54_get_band_from_freq(freq);
+
+ /*
+ * filter out frequencies which don't belong into
+ * any supported band.
+ */
+ if (band < 0)
+ return ;
+
+ i = list->entries++;
+ list->band_channel_num[band]++;
+
+ list->channels[i].freq = freq;
+ list->channels[i].data = data;
+ list->channels[i].band = band;
+ list->channels[i].index = ieee80211_frequency_to_channel(freq);
+ /* TODO: parse output_limit and fill max_power */
+ }
+}
+
+static int p54_generate_channel_lists(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_channel_list *list;
+ unsigned int i, j, max_channel_num;
+ int ret = -ENOMEM;
+ u16 freq;
+
+ if ((priv->iq_autocal_len != priv->curve_data->entries) ||
+ (priv->iq_autocal_len != priv->output_limit->entries))
+ printk(KERN_ERR "%s: EEPROM is damaged... you may not be able"
+ "to use all channels with this device.\n",
+ wiphy_name(dev->wiphy));
+
+ max_channel_num = max_t(unsigned int, priv->output_limit->entries,
+ priv->iq_autocal_len);
+ max_channel_num = max_t(unsigned int, max_channel_num,
+ priv->curve_data->entries);
+
+ list = kzalloc(sizeof(*list), GFP_KERNEL);
+ if (!list)
+ goto free;
+
+ list->max_entries = max_channel_num;
+ list->channels = kzalloc(sizeof(struct p54_channel_entry) *
+ max_channel_num, GFP_KERNEL);
+ if (!list->channels)
+ goto free;
+
+ for (i = 0; i < max_channel_num; i++) {
+ if (i < priv->iq_autocal_len) {
+ freq = le16_to_cpu(priv->iq_autocal[i].freq);
+ p54_update_channel_param(list, freq, CHAN_HAS_CAL);
+ }
+
+ if (i < priv->output_limit->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->output_limit->entry_size +
+ priv->output_limit->offset +
+ priv->output_limit->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
+ }
+
+ if (i < priv->curve_data->entries) {
+ freq = le16_to_cpup((__le16 *) (i *
+ priv->curve_data->entry_size +
+ priv->curve_data->offset +
+ priv->curve_data->data));
+
+ p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
+ }
+ }
+
+ /* sort the list by the channel index */
+ sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
+ p54_compare_channels, NULL);
+
+ for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
+ if (list->band_channel_num[i]) {
+ ret = p54_generate_band(dev, list, i);
+ if (ret)
+ goto free;
+
+ j++;
+ }
+ }
+ if (j == 0) {
+ /* no useable band available. */
+ ret = -EINVAL;
+ }
+
+free:
+ if (list) {
+ kfree(list->channels);
+ kfree(list);
+ }
+
+ return ret;
+}
+
+static int p54_convert_rev0(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_pa_curve_data_sample *dst;
+ struct pda_pa_curve_data_sample_rev0 *src;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*dst) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
+ GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ priv->curve_data->entries = curve_data->channels;
+ priv->curve_data->entry_size = sizeof(__le16) +
+ sizeof(*dst) * curve_data->points_per_channel;
+ priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+ priv->curve_data->len = cd_len;
+ memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ dst = target;
+ src = source;
+
+ dst->rf_power = src->rf_power;
+ dst->pa_detector = src->pa_detector;
+ dst->data_64qam = src->pcv;
+ /* "invent" the points for the other modulations */
+#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
+ dst->data_16qam = SUB(src->pcv, 12);
+ dst->data_qpsk = SUB(dst->data_16qam, 12);
+ dst->data_bpsk = SUB(dst->data_qpsk, 12);
+ dst->data_barker = SUB(dst->data_bpsk, 14);
+#undef SUB
+ target += sizeof(*dst);
+ source += sizeof(*src);
+ }
+ }
+
+ return 0;
+}
+
+static int p54_convert_rev1(struct ieee80211_hw *dev,
+ struct pda_pa_curve_data *curve_data)
+{
+ struct p54_common *priv = dev->priv;
+ struct p54_pa_curve_data_sample *dst;
+ struct pda_pa_curve_data_sample_rev1 *src;
+ size_t cd_len = sizeof(*curve_data) +
+ (curve_data->points_per_channel*sizeof(*dst) + 2) *
+ curve_data->channels;
+ unsigned int i, j;
+ void *source, *target;
+
+ priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
+ GFP_KERNEL);
+ if (!priv->curve_data)
+ return -ENOMEM;
+
+ priv->curve_data->entries = curve_data->channels;
+ priv->curve_data->entry_size = sizeof(__le16) +
+ sizeof(*dst) * curve_data->points_per_channel;
+ priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+ priv->curve_data->len = cd_len;
+ memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+ source = curve_data->data;
+ target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+ for (i = 0; i < curve_data->channels; i++) {
+ __le16 *freq = source;
+ source += sizeof(__le16);
+ *((__le16 *)target) = *freq;
+ target += sizeof(__le16);
+ for (j = 0; j < curve_data->points_per_channel; j++) {
+ memcpy(target, source, sizeof(*src));
+
+ target += sizeof(*dst);
+ source += sizeof(*src);
+ }
+ source++;
+ }
+
+ return 0;
+}
+
+static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
+ "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
+
+static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
+ u16 type)
+{
+ struct p54_common *priv = dev->priv;
+ int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
+ int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
+ int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+ int i;
+
+ if (len != (entry_size * num_entries)) {
+ printk(KERN_ERR "%s: unknown rssi calibration data packing "
+ " type:(%x) len:%d.\n",
+ wiphy_name(dev->wiphy), type, len);
+
+ print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ for (i = 0; i < num_entries; i++) {
+ struct pda_rssi_cal_entry *cal = data +
+ (offset + i * entry_size);
+ priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
+ priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
+ }
+}
+
+static void p54_parse_default_country(struct ieee80211_hw *dev,
+ void *data, int len)
+{
+ struct pda_country *country;
+
+ if (len != sizeof(*country)) {
+ printk(KERN_ERR "%s: found possible invalid default country "
+ "eeprom entry. (entry size: %d)\n",
+ wiphy_name(dev->wiphy), len);
+
+ print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
+ data, len);
+
+ printk(KERN_ERR "%s: please report this issue.\n",
+ wiphy_name(dev->wiphy));
+ return;
+ }
+
+ country = (struct pda_country *) data;
+ if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
+ regulatory_hint(dev->wiphy, country->alpha2);
+ else {
+ /* TODO:
+ * write a shared/common function that converts
+ * "Regulatory domain codes" (802.11-2007 14.8.2.2)
+ * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
+ */
+ }
+}
+
+static int p54_convert_output_limits(struct ieee80211_hw *dev,
+ u8 *data, size_t len)
+{
+ struct p54_common *priv = dev->priv;
+
+ if (len < 2)
+ return -EINVAL;
+
+ if (data[0] != 0) {
+ printk(KERN_ERR "%s: unknown output power db revision:%x\n",
+ wiphy_name(dev->wiphy), data[0]);
+ return -EINVAL;
+ }
+
+ if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
+ return -EINVAL;
+
+ priv->output_limit = kmalloc(data[1] *
+ sizeof(struct pda_channel_output_limit) +
+ sizeof(*priv->output_limit), GFP_KERNEL);
+
+ if (!priv->output_limit)
+ return -ENOMEM;
+
+ priv->output_limit->offset = 0;
+ priv->output_limit->entries = data[1];
+ priv->output_limit->entry_size =
+ sizeof(struct pda_channel_output_limit);
+ priv->output_limit->len = priv->output_limit->entry_size *
+ priv->output_limit->entries +
+ priv->output_limit->offset;
+
+ memcpy(priv->output_limit->data, &data[2],
+ data[1] * sizeof(struct pda_channel_output_limit));
+
+ return 0;
+}
+
+static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
+ size_t total_len)
+{
+ struct p54_cal_database *dst;
+ size_t payload_len, entries, entry_size, offset;
+
+ payload_len = le16_to_cpu(src->len);
+ entries = le16_to_cpu(src->entries);
+ entry_size = le16_to_cpu(src->entry_size);
+ offset = le16_to_cpu(src->offset);
+ if (((entries * entry_size + offset) != payload_len) ||
+ (payload_len + sizeof(*src) != total_len))
+ return NULL;
+
+ dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
+ if (!dst)
+ return NULL;
+
+ dst->entries = entries;
+ dst->entry_size = entry_size;
+ dst->offset = offset;
+ dst->len = payload_len;
+
+ memcpy(dst->data, src->data, payload_len);
+ return dst;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+ struct p54_common *priv = dev->priv;
+ struct eeprom_pda_wrap *wrap;
+ struct pda_entry *entry;
+ unsigned int data_len, entry_len;
+ void *tmp;
+ int err;
+ u8 *end = (u8 *)eeprom + len;
+ u16 synth = 0;
+
+ wrap = (struct eeprom_pda_wrap *) eeprom;
+ entry = (void *)wrap->data + le16_to_cpu(wrap->len);
+
+ /* verify that at least the entry length/code fits */
+ while ((u8 *)entry <= end - sizeof(*entry)) {
+ entry_len = le16_to_cpu(entry->len);
+ data_len = ((entry_len - 1) << 1);
+
+ /* abort if entry exceeds whole structure */
+ if ((u8 *)entry + sizeof(*entry) + data_len > end)
+ break;
+
+ switch (le16_to_cpu(entry->code)) {
+ case PDR_MAC_ADDRESS:
+ if (data_len != ETH_ALEN)
+ break;
+ SET_IEEE80211_PERM_ADDR(dev, entry->data);
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+ if (priv->output_limit)
+ break;
+ err = p54_convert_output_limits(dev, entry->data,
+ data_len);
+ if (err)
+ goto err;
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA: {
+ struct pda_pa_curve_data *curve_data =
+ (struct pda_pa_curve_data *)entry->data;
+ if (data_len < sizeof(*curve_data)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ switch (curve_data->cal_method_rev) {
+ case 0:
+ err = p54_convert_rev0(dev, curve_data);
+ break;
+ case 1:
+ err = p54_convert_rev1(dev, curve_data);
+ break;
+ default:
+ printk(KERN_ERR "%s: unknown curve data "
+ "revision %d\n",
+ wiphy_name(dev->wiphy),
+ curve_data->cal_method_rev);
+ err = -ENODEV;
+ break;
+ }
+ if (err)
+ goto err;
+ }
+ break;
+ case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+ priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+ if (!priv->iq_autocal) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(priv->iq_autocal, entry->data, data_len);
+ priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+ break;
+ case PDR_DEFAULT_COUNTRY:
+ p54_parse_default_country(dev, entry->data, data_len);
+ break;
+ case PDR_INTERFACE_LIST:
+ tmp = entry->data;
+ while ((u8 *)tmp < entry->data + data_len) {
+ struct exp_if *exp_if = tmp;
+ if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
+ synth = le16_to_cpu(exp_if->variant);
+ tmp += sizeof(*exp_if);
+ }
+ break;
+ case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+ if (data_len < 2)
+ break;
+ priv->version = *(u8 *)(entry->data + 1);
+ break;
+ case PDR_RSSI_LINEAR_APPROXIMATION:
+ case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+ case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+ p54_parse_rssical(dev, entry->data, data_len,
+ le16_to_cpu(entry->code));
+ break;
+ case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
+ __le16 *src = (void *) entry->data;
+ s16 *dst = (void *) &priv->rssical_db;
+ int i;
+
+ if (data_len != sizeof(priv->rssical_db)) {
+ err = -EINVAL;
+ goto err;
+ }
+ for (i = 0; i < sizeof(priv->rssical_db) /
+ sizeof(*src); i++)
+ *(dst++) = (s16) le16_to_cpu(*(src++));
+ }
+ break;
+ case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
+ struct pda_custom_wrapper *pda = (void *) entry->data;
+ if (priv->output_limit || data_len < sizeof(*pda))
+ break;
+ priv->output_limit = p54_convert_db(pda, data_len);
+ }
+ break;
+ case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
+ struct pda_custom_wrapper *pda = (void *) entry->data;
+ if (priv->curve_data || data_len < sizeof(*pda))
+ break;
+ priv->curve_data = p54_convert_db(pda, data_len);
+ }
+ break;
+ case PDR_END:
+ /* make it overrun */
+ entry_len = len;
+ break;
+ default:
+ break;
+ }
+
+ entry = (void *)entry + (entry_len + 1)*2;
+ }
+
+ if (!synth || !priv->iq_autocal || !priv->output_limit ||
+ !priv->curve_data) {
+ printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
+ wiphy_name(dev->wiphy));
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = p54_generate_channel_lists(dev);
+ if (err)
+ goto err;
+
+ priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
+ p54_init_xbow_synth(priv);
+ if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
+ dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+ priv->band_table[IEEE80211_BAND_2GHZ];
+ if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
+ dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ priv->band_table[IEEE80211_BAND_5GHZ];
+ if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
+ priv->rx_diversity_mask = 3;
+ if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
+ priv->tx_diversity_mask = 3;
+
+ if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+ u8 perm_addr[ETH_ALEN];
+
+ printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
+ wiphy_name(dev->wiphy));
+ random_ether_addr(perm_addr);
+ SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+ }
+
+ printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
+ wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version,
+ p54_rf_chips[priv->rxhw]);
+
+ return 0;
+
+err:
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ priv->iq_autocal = NULL;
+ priv->output_limit = NULL;
+ priv->curve_data = NULL;
+
+ printk(KERN_ERR "%s: eeprom parse failed!\n",
+ wiphy_name(dev->wiphy));
+ return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+int p54_read_eeprom(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
+ int ret = -ENOMEM;
+ void *eeprom;
+
+ maxblocksize = EEPROM_READBACK_LEN;
+ if (priv->fw_var >= 0x509)
+ maxblocksize -= 0xc;
+ else
+ maxblocksize -= 0x4;
+
+ eeprom = kzalloc(eeprom_size, GFP_KERNEL);
+ if (unlikely(!eeprom))
+ goto free;
+
+ while (eeprom_size) {
+ blocksize = min(eeprom_size, maxblocksize);
+ ret = p54_download_eeprom(priv, (void *) (eeprom + offset),
+ offset, blocksize);
+ if (unlikely(ret))
+ goto free;
+
+ offset += blocksize;
+ eeprom_size -= blocksize;
+ }
+
+ ret = p54_parse_eeprom(dev, eeprom, offset);
+free:
+ kfree(eeprom);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(p54_read_eeprom);
diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h
new file mode 100644
index 00000000000..9051aef1124
--- /dev/null
+++ b/drivers/net/wireless/p54/eeprom.h
@@ -0,0 +1,226 @@
+/*
+ * eeprom specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * - islmvc driver
+ * Copyright (C) 2001 Intersil Americas Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef EEPROM_H
+#define EEPROM_H
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+ __le16 len; /* includes both code and data */
+ __le16 code;
+ u8 data[0];
+} __packed;
+
+struct eeprom_pda_wrap {
+ __le32 magic;
+ __le16 pad;
+ __le16 len;
+ __le32 arm_opcode;
+ u8 data[0];
+} __packed;
+
+struct p54_iq_autocal_entry {
+ __le16 iq_param[4];
+} __packed;
+
+struct pda_iq_autocal_entry {
+ __le16 freq;
+ struct p54_iq_autocal_entry params;
+} __packed;
+
+struct pda_channel_output_limit {
+ __le16 freq;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ u8 rate_set_mask;
+ u8 rate_set_size;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev0 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 pcv;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev1 {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+} __packed;
+
+struct pda_pa_curve_data {
+ u8 cal_method_rev;
+ u8 channels;
+ u8 points_per_channel;
+ u8 padding;
+ u8 data[0];
+} __packed;
+
+struct pda_rssi_cal_entry {
+ __le16 mul;
+ __le16 add;
+} __packed;
+
+struct pda_country {
+ u8 regdomain;
+ u8 alpha2[2];
+ u8 flags;
+} __packed;
+
+struct pda_antenna_gain {
+ struct {
+ u8 gain_5GHz; /* 0.25 dBi units */
+ u8 gain_2GHz; /* 0.25 dBi units */
+ } __packed antenna[0];
+} __packed;
+
+struct pda_custom_wrapper {
+ __le16 entries;
+ __le16 entry_size;
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+} __packed;
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END 0x0000
+#define PDR_MANUFACTURING_PART_NUMBER 0x0001
+#define PDR_PDA_VERSION 0x0002
+#define PDR_NIC_SERIAL_NUMBER 0x0003
+#define PDR_NIC_RAM_SIZE 0x0005
+#define PDR_RFMODEM_SUP_RANGE 0x0006
+#define PDR_PRISM_MAC_SUP_RANGE 0x0007
+#define PDR_NIC_ID 0x0008
+
+#define PDR_MAC_ADDRESS 0x0101
+#define PDR_REGULATORY_DOMAIN_LIST 0x0103 /* obsolete */
+#define PDR_ALLOWED_CHAN_SET 0x0104
+#define PDR_DEFAULT_CHAN 0x0105
+#define PDR_TEMPERATURE_TYPE 0x0107
+
+#define PDR_IFR_SETTING 0x0200
+#define PDR_RFR_SETTING 0x0201
+#define PDR_3861_BASELINE_REG_SETTINGS 0x0202
+#define PDR_3861_SHADOW_REG_SETTINGS 0x0203
+#define PDR_3861_IFRF_REG_SETTINGS 0x0204
+
+#define PDR_3861_CHAN_CALIB_SET_POINTS 0x0300
+#define PDR_3861_CHAN_CALIB_INTEGRATOR 0x0301
+
+#define PDR_3842_PRISM_II_NIC_CONFIG 0x0400
+#define PDR_PRISM_USB_ID 0x0401
+#define PDR_PRISM_PCI_ID 0x0402
+#define PDR_PRISM_PCI_IF_CONFIG 0x0403
+#define PDR_PRISM_PCI_PM_CONFIG 0x0404
+
+#define PDR_3861_MF_TEST_CHAN_SET_POINTS 0x0900
+#define PDR_3861_MF_TEST_CHAN_INTEGRATORS 0x0901
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION 0x1000 /* obsolete */
+#define PDR_INTERFACE_LIST 0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
+#define PDR_OEM_NAME 0x1003
+#define PDR_PRODUCT_NAME 0x1004
+#define PDR_UTF8_OEM_NAME 0x1005
+#define PDR_UTF8_PRODUCT_NAME 0x1006
+#define PDR_COUNTRY_LIST 0x1007
+#define PDR_DEFAULT_COUNTRY 0x1008
+
+#define PDR_ANTENNA_GAIN 0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
+#define PDR_REGULATORY_POWER_LIMITS 0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS 0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
+
+/* used by our modificated eeprom image */
+#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF
+#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D
+
+/* Interface Definitions */
+#define PDR_INTERFACE_ROLE_SERVER 0x0000
+#define PDR_INTERFACE_ROLE_CLIENT 0x0001
+
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE 0x80
+#define PDR_COUNTRY_CERT_CODE_REAL 0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
+#define PDR_COUNTRY_CERT_BAND 0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
+#define PDR_COUNTRY_CERT_IODOOR 0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
+#define PDR_COUNTRY_CERT_INDEX 0x0f
+
+/* Specific LMAC FW/HW variant definitions */
+#define PDR_SYNTH_FRONTEND_MASK 0x0007
+#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001
+#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002
+#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003
+#define PDR_SYNTH_FRONTEND_XBOW 0x0004
+#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005
+#define PDR_SYNTH_IQ_CAL_MASK 0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020
+#define PDR_SYNTH_24_GHZ_MASK 0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
+#define PDR_SYNTH_5_GHZ_MASK 0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
+#define PDR_SYNTH_RX_DIV_MASK 0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
+#define PDR_SYNTH_TX_DIV_MASK 0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
+#define PDR_SYNTH_ASM_MASK 0x0400
+#define PDR_SYNTH_ASM_XSWON 0x0400
+
+#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
new file mode 100644
index 00000000000..21f19018fab
--- /dev/null
+++ b/drivers/net/wireless/p54/fwio.c
@@ -0,0 +1,715 @@
+/*
+ * Firmware I/O code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+ struct p54_common *priv = dev->priv;
+ struct exp_if *exp_if;
+ struct bootrec *bootrec;
+ u32 *data = (u32 *)fw->data;
+ u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+ u8 *fw_version = NULL;
+ size_t len;
+ int i;
+ int maxlen;
+
+ if (priv->rx_start)
+ return 0;
+
+ while (data < end_data && *data)
+ data++;
+
+ while (data < end_data && !*data)
+ data++;
+
+ bootrec = (struct bootrec *) data;
+
+ while (bootrec->data <= end_data && (bootrec->data +
+ (len = le32_to_cpu(bootrec->len))) <= end_data) {
+ u32 code = le32_to_cpu(bootrec->code);
+ switch (code) {
+ case BR_CODE_COMPONENT_ID:
+ priv->fw_interface = be32_to_cpup((__be32 *)
+ bootrec->data);
+ switch (priv->fw_interface) {
+ case FW_LM86:
+ case FW_LM20:
+ case FW_LM87: {
+ char *iftype = (char *)bootrec->data;
+ printk(KERN_INFO "%s: p54 detected a LM%c%c "
+ "firmware\n",
+ wiphy_name(priv->hw->wiphy),
+ iftype[2], iftype[3]);
+ break;
+ }
+ case FW_FMAC:
+ default:
+ printk(KERN_ERR "%s: unsupported firmware\n",
+ wiphy_name(priv->hw->wiphy));
+ return -ENODEV;
+ }
+ break;
+ case BR_CODE_COMPONENT_VERSION:
+ /* 24 bytes should be enough for all firmwares */
+ if (strnlen((unsigned char *) bootrec->data, 24) < 24)
+ fw_version = (unsigned char *) bootrec->data;
+ break;
+ case BR_CODE_DESCR: {
+ struct bootrec_desc *desc =
+ (struct bootrec_desc *)bootrec->data;
+ priv->rx_start = le32_to_cpu(desc->rx_start);
+ /* FIXME add sanity checking */
+ priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
+ priv->headroom = desc->headroom;
+ priv->tailroom = desc->tailroom;
+ priv->privacy_caps = desc->privacy_caps;
+ priv->rx_keycache_size = desc->rx_keycache_size;
+ if (le32_to_cpu(bootrec->len) == 11)
+ priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
+ else
+ priv->rx_mtu = (size_t)
+ 0x620 - priv->tx_hdr_len;
+ maxlen = priv->tx_hdr_len + /* USB devices */
+ sizeof(struct p54_rx_data) +
+ 4 + /* rx alignment */
+ IEEE80211_MAX_FRAG_THRESHOLD;
+ if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
+ printk(KERN_INFO "p54: rx_mtu reduced from %d "
+ "to %d\n", priv->rx_mtu, maxlen);
+ priv->rx_mtu = maxlen;
+ }
+ break;
+ }
+ case BR_CODE_EXPOSED_IF:
+ exp_if = (struct exp_if *) bootrec->data;
+ for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+ if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC))
+ priv->fw_var = le16_to_cpu(exp_if[i].variant);
+ break;
+ case BR_CODE_DEPENDENT_IF:
+ break;
+ case BR_CODE_END_OF_BRA:
+ case LEGACY_BR_CODE_END_OF_BRA:
+ end_data = NULL;
+ break;
+ default:
+ break;
+ }
+ bootrec = (struct bootrec *)&bootrec->data[len];
+ }
+
+ if (fw_version)
+ printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
+ wiphy_name(priv->hw->wiphy), fw_version,
+ priv->fw_var >> 8, priv->fw_var & 0xff);
+
+ if (priv->fw_var < 0x500)
+ printk(KERN_INFO "%s: you are using an obsolete firmware. "
+ "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+ "and grab one for \"kernel >= 2.6.28\"!\n",
+ wiphy_name(priv->hw->wiphy));
+
+ if (priv->fw_var >= 0x300) {
+ /* Firmware supports QoS, use it! */
+
+ if (priv->fw_var >= 0x500) {
+ priv->tx_stats[P54_QUEUE_AC_VO].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_VI].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_BE].limit = 16;
+ priv->tx_stats[P54_QUEUE_AC_BK].limit = 16;
+ } else {
+ priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
+ priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
+ priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
+ priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
+ }
+ priv->hw->queues = P54_QUEUE_AC_NUM;
+ }
+
+ printk(KERN_INFO "%s: cryptographic accelerator "
+ "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(priv->hw->wiphy),
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
+ "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
+ BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
+ (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
+ "YES" : "no");
+
+ if (priv->rx_keycache_size) {
+ /*
+ * NOTE:
+ *
+ * The firmware provides at most 255 (0 - 254) slots
+ * for keys which are then used to offload decryption.
+ * As a result the 255 entry (aka 0xff) can be used
+ * safely by the driver to mark keys that didn't fit
+ * into the full cache. This trick saves us from
+ * keeping a extra list for uploaded keys.
+ */
+
+ priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
+ priv->rx_keycache_size), GFP_KERNEL);
+
+ if (!priv->used_rxkeys)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags,
+ u16 payload_len, u16 type, gfp_t memflags)
+{
+ struct p54_hdr *hdr;
+ struct sk_buff *skb;
+ size_t frame_len = sizeof(*hdr) + payload_len;
+
+ if (frame_len > P54_MAX_CTRL_FRAME_LEN)
+ return NULL;
+
+ if (unlikely(skb_queue_len(&priv->tx_pending) > 64))
+ return NULL;
+
+ skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
+ if (!skb)
+ return NULL;
+ skb_reserve(skb, priv->tx_hdr_len);
+
+ hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->len = cpu_to_le16(payload_len);
+ hdr->type = cpu_to_le16(type);
+ hdr->tries = hdr->rts_tries = 0;
+ return skb;
+}
+
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+ u16 offset, u16 len)
+{
+ struct p54_eeprom_lm86 *eeprom_hdr;
+ struct sk_buff *skb;
+ size_t eeprom_hdr_size;
+ int ret = 0;
+
+ if (priv->fw_var >= 0x509)
+ eeprom_hdr_size = sizeof(*eeprom_hdr);
+ else
+ eeprom_hdr_size = 0x4;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size +
+ len, P54_CONTROL_TYPE_EEPROM_READBACK,
+ GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ mutex_lock(&priv->eeprom_mutex);
+ priv->eeprom = buf;
+ eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
+ eeprom_hdr_size + len);
+
+ if (priv->fw_var < 0x509) {
+ eeprom_hdr->v1.offset = cpu_to_le16(offset);
+ eeprom_hdr->v1.len = cpu_to_le16(len);
+ } else {
+ eeprom_hdr->v2.offset = cpu_to_le32(offset);
+ eeprom_hdr->v2.len = cpu_to_le16(len);
+ eeprom_hdr->v2.magic2 = 0xf;
+ memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
+ }
+
+ p54_tx(priv, skb);
+
+ if (!wait_for_completion_interruptible_timeout(
+ &priv->eeprom_comp, HZ)) {
+ printk(KERN_ERR "%s: device does not respond!\n",
+ wiphy_name(priv->hw->wiphy));
+ ret = -EBUSY;
+ }
+ priv->eeprom = NULL;
+ mutex_unlock(&priv->eeprom_mutex);
+ return ret;
+}
+
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set)
+{
+ struct sk_buff *skb;
+ struct p54_tim *tim;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
+ P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+ tim->count = 1;
+ tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_sta_unlock(struct p54_common *priv, u8 *addr)
+{
+ struct sk_buff *skb;
+ struct p54_sta_unlock *sta;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+ memcpy(sta->addr, addr, ETH_ALEN);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
+{
+ struct sk_buff *skb;
+ struct p54_txcancel *cancel;
+ u32 _req_id = le32_to_cpu(req_id);
+
+ if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
+ return -EINVAL;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
+ P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+ cancel->req_id = req_id;
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_setup_mac(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_setup_mac *setup;
+ u16 mode;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
+ P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
+ if (priv->hw->conf.radio_enabled) {
+ switch (priv->mode) {
+ case NL80211_IFTYPE_STATION:
+ mode = P54_FILTER_TYPE_STATION;
+ break;
+ case NL80211_IFTYPE_AP:
+ mode = P54_FILTER_TYPE_AP;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ mode = P54_FILTER_TYPE_IBSS;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ mode = P54_FILTER_TYPE_PROMISCUOUS;
+ break;
+ default:
+ mode = P54_FILTER_TYPE_HIBERNATE;
+ break;
+ }
+
+ /*
+ * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
+ * STSW45X0C LMAC API - page 12
+ */
+ if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
+ (priv->filter_flags & FIF_OTHER_BSS)) &&
+ (mode != P54_FILTER_TYPE_PROMISCUOUS))
+ mode |= P54_FILTER_TYPE_TRANSPARENT;
+ } else
+ mode = P54_FILTER_TYPE_HIBERNATE;
+
+ setup->mac_mode = cpu_to_le16(mode);
+ memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
+ memcpy(setup->bssid, priv->bssid, ETH_ALEN);
+ setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
+ setup->rx_align = 0;
+ if (priv->fw_var < 0x500) {
+ setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ memset(setup->v1.rts_rates, 0, 8);
+ setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v1.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v1.unalloc0 = cpu_to_le16(0);
+ } else {
+ setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
+ setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+ setup->v2.rxhw = cpu_to_le16(priv->rxhw);
+ setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
+ setup->v2.truncate = cpu_to_le16(48896);
+ setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ setup->v2.sbss_offset = 0;
+ setup->v2.mcast_window = 0;
+ setup->v2.rx_rssi_threshold = 0;
+ setup->v2.rx_ed_threshold = 0;
+ setup->v2.ref_clock = cpu_to_le32(644245094);
+ setup->v2.lpf_bandwidth = cpu_to_le16(65535);
+ setup->v2.osc_start_delay = cpu_to_le16(65535);
+ }
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
+{
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ struct p54_scan_head *head;
+ struct p54_iq_autocal_entry *iq_autocal;
+ union p54_scan_body_union *body;
+ struct p54_scan_tail_rate *rate;
+ struct pda_rssi_cal_entry *rssi;
+ unsigned int i;
+ void *entry;
+ int band = priv->hw->conf.channel->band;
+ __le16 freq = cpu_to_le16(priv->hw->conf.channel->center_freq);
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
+ 2 + sizeof(*iq_autocal) + sizeof(*body) +
+ sizeof(*rate) + 2 * sizeof(*rssi),
+ P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
+ memset(head->scan_params, 0, sizeof(head->scan_params));
+ head->mode = cpu_to_le16(mode);
+ head->dwell = cpu_to_le16(dwell);
+ head->freq = freq;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
+ *pa_power_points = cpu_to_le16(0x0c);
+ }
+
+ iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
+ for (i = 0; i < priv->iq_autocal_len; i++) {
+ if (priv->iq_autocal[i].freq != freq)
+ continue;
+
+ memcpy(iq_autocal, &priv->iq_autocal[i].params,
+ sizeof(struct p54_iq_autocal_entry));
+ break;
+ }
+ if (i == priv->iq_autocal_len)
+ goto err;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
+ body = (void *) skb_put(skb, sizeof(body->longbow));
+ else
+ body = (void *) skb_put(skb, sizeof(body->normal));
+
+ for (i = 0; i < priv->output_limit->entries; i++) {
+ __le16 *entry_freq = (void *) (priv->output_limit->data +
+ priv->output_limit->entry_size * i);
+
+ if (*entry_freq != freq)
+ continue;
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ memcpy(&body->longbow.power_limits,
+ (void *) entry_freq + sizeof(__le16),
+ priv->output_limit->entry_size);
+ } else {
+ struct pda_channel_output_limit *limits =
+ (void *) entry_freq;
+
+ body->normal.val_barker = 0x38;
+ body->normal.val_bpsk = body->normal.dup_bpsk =
+ limits->val_bpsk;
+ body->normal.val_qpsk = body->normal.dup_qpsk =
+ limits->val_qpsk;
+ body->normal.val_16qam = body->normal.dup_16qam =
+ limits->val_16qam;
+ body->normal.val_64qam = body->normal.dup_64qam =
+ limits->val_64qam;
+ }
+ break;
+ }
+ if (i == priv->output_limit->entries)
+ goto err;
+
+ entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
+ for (i = 0; i < priv->curve_data->entries; i++) {
+ if (*((__le16 *)entry) != freq) {
+ entry += priv->curve_data->entry_size;
+ continue;
+ }
+
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ memcpy(&body->longbow.curve_data,
+ (void *) entry + sizeof(__le16),
+ priv->curve_data->entry_size);
+ } else {
+ struct p54_scan_body *chan = &body->normal;
+ struct pda_pa_curve_data *curve_data =
+ (void *) priv->curve_data->data;
+
+ entry += sizeof(__le16);
+ chan->pa_points_per_curve = 8;
+ memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+ memcpy(chan->curve_data, entry,
+ sizeof(struct p54_pa_curve_data_sample) *
+ min((u8)8, curve_data->points_per_channel));
+ }
+ break;
+ }
+ if (i == priv->curve_data->entries)
+ goto err;
+
+ if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
+ rate = (void *) skb_put(skb, sizeof(*rate));
+ rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ for (i = 0; i < sizeof(rate->rts_rates); i++)
+ rate->rts_rates[i] = i;
+ }
+
+ rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
+ rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
+ rssi->add = cpu_to_le16(priv->rssical_db[band].add);
+ if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+ /* Longbow frontend needs ever more */
+ rssi = (void *) skb_put(skb, sizeof(*rssi));
+ rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
+ rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
+ }
+
+ if (priv->fw_var >= 0x509) {
+ rate = (void *) skb_put(skb, sizeof(*rate));
+ rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+ for (i = 0; i < sizeof(rate->rts_rates); i++)
+ rate->rts_rates[i] = i;
+ }
+
+ hdr = (struct p54_hdr *) skb->data;
+ hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
+
+ p54_tx(priv, skb);
+ return 0;
+
+err:
+ printk(KERN_ERR "%s: frequency change to channel %d failed.\n",
+ wiphy_name(priv->hw->wiphy), ieee80211_frequency_to_channel(
+ priv->hw->conf.channel->center_freq));
+
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+}
+
+int p54_set_leds(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_led *led;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
+ P54_CONTROL_TYPE_LED, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ led = (struct p54_led *) skb_put(skb, sizeof(*led));
+ led->flags = cpu_to_le16(0x0003);
+ led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
+ led->delay[0] = cpu_to_le16(1);
+ led->delay[1] = cpu_to_le16(0);
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_set_edcf(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_edcf *edcf;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
+ P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
+ if (priv->use_short_slot) {
+ edcf->slottime = 9;
+ edcf->sifs = 0x10;
+ edcf->eofpad = 0x00;
+ } else {
+ edcf->slottime = 20;
+ edcf->sifs = 0x0a;
+ edcf->eofpad = 0x06;
+ }
+ /* (see prism54/isl_oid.h for further details) */
+ edcf->frameburst = cpu_to_le16(0);
+ edcf->round_trip_delay = cpu_to_le16(0);
+ edcf->flags = 0;
+ memset(edcf->mapping, 0, sizeof(edcf->mapping));
+ memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_set_ps(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_psm *psm;
+ unsigned int i;
+ u16 mode;
+
+ if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
+ !priv->powersave_override)
+ mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
+ P54_PSM_CHECKSUM | P54_PSM_MCBC;
+ else
+ mode = P54_PSM_CAM;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
+ P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
+ psm->mode = cpu_to_le16(mode);
+ psm->aid = cpu_to_le16(priv->aid);
+ for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
+ psm->intervals[i].interval =
+ cpu_to_le16(priv->hw->conf.listen_interval);
+ psm->intervals[i].periods = cpu_to_le16(1);
+ }
+
+ psm->beacon_rssi_skip_max = 200;
+ psm->rssi_delta_threshold = 0;
+ psm->nr = 1;
+ psm->exclude[0] = WLAN_EID_TIM;
+
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_init_xbow_synth(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ struct p54_xbow_synth *xbow;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
+ xbow->magic1 = cpu_to_le16(0x1);
+ xbow->magic2 = cpu_to_le16(0x2);
+ xbow->freq = cpu_to_le16(5390);
+ memset(xbow->padding, 0, sizeof(xbow->padding));
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
+ u8 *addr, u8* key)
+{
+ struct sk_buff *skb;
+ struct p54_keycache *rxkey;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
+ P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
+ rxkey->entry = slot;
+ rxkey->key_id = idx;
+ rxkey->key_type = algo;
+ if (addr)
+ memcpy(rxkey->mac, addr, ETH_ALEN);
+ else
+ memset(rxkey->mac, ~0, ETH_ALEN);
+
+ switch (algo) {
+ case P54_CRYPTO_WEP:
+ case P54_CRYPTO_AESCCMP:
+ rxkey->key_len = min_t(u8, 16, len);
+ memcpy(rxkey->key, key, rxkey->key_len);
+ break;
+
+ case P54_CRYPTO_TKIPMICHAEL:
+ rxkey->key_len = 24;
+ memcpy(rxkey->key, key, 16);
+ memcpy(&(rxkey->key[16]), &(key
+ [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
+ break;
+
+ case P54_CRYPTO_NONE:
+ rxkey->key_len = 0;
+ memset(rxkey->key, 0, sizeof(rxkey->key));
+ break;
+
+ default:
+ printk(KERN_ERR "%s: invalid cryptographic algorithm: %d\n",
+ wiphy_name(priv->hw->wiphy), algo);
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ p54_tx(priv, skb);
+ return 0;
+}
+
+int p54_fetch_statistics(struct p54_common *priv)
+{
+ struct ieee80211_tx_info *txinfo;
+ struct p54_tx_info *p54info;
+ struct sk_buff *skb;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
+ sizeof(struct p54_statistics),
+ P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ /*
+ * The statistic feedback causes some extra headaches here, if it
+ * is not to crash/corrupt the firmware data structures.
+ *
+ * Unlike all other Control Get OIDs we can not use helpers like
+ * skb_put to reserve the space for the data we're requesting.
+ * Instead the extra frame length -which will hold the results later-
+ * will only be told to the p54_assign_address, so that following
+ * frames won't be placed into the allegedly empty area.
+ */
+ txinfo = IEEE80211_SKB_CB(skb);
+ p54info = (void *) txinfo->rate_driver_data;
+ p54info->extra_len = sizeof(struct p54_statistics);
+
+ p54_tx(priv, skb);
+ return 0;
+}
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
new file mode 100644
index 00000000000..c00115b206d
--- /dev/null
+++ b/drivers/net/wireless/p54/led.c
@@ -0,0 +1,163 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+#ifdef CONFIG_P54_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_P54_LEDS */
+
+#include "p54.h"
+#include "lmac.h"
+
+static void p54_update_leds(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ led_work.work);
+ int err, i, tmp, blink_delay = 400;
+ bool rerun = false;
+
+ /* Don't toggle the LED, when the device is down. */
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
+ if (priv->leds[i].toggled) {
+ priv->softled_state |= BIT(i);
+
+ tmp = 70 + 200 / (priv->leds[i].toggled);
+ if (tmp < blink_delay)
+ blink_delay = tmp;
+
+ if (priv->leds[i].led_dev.brightness == LED_OFF)
+ rerun = true;
+
+ priv->leds[i].toggled =
+ !!priv->leds[i].led_dev.brightness;
+ } else
+ priv->softled_state &= ~BIT(i);
+
+ err = p54_set_leds(priv);
+ if (err && net_ratelimit())
+ printk(KERN_ERR "%s: failed to update LEDs (%d).\n",
+ wiphy_name(priv->hw->wiphy), err);
+
+ if (rerun)
+ queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ msecs_to_jiffies(blink_delay));
+}
+
+static void p54_led_brightness_set(struct led_classdev *led_dev,
+ enum led_brightness brightness)
+{
+ struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
+ led_dev);
+ struct ieee80211_hw *dev = led->hw_dev;
+ struct p54_common *priv = dev->priv;
+
+ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+ return ;
+
+ if ((brightness) && (led->registered)) {
+ led->toggled++;
+ queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ HZ/10);
+ }
+}
+
+static int p54_register_led(struct p54_common *priv,
+ unsigned int led_index,
+ char *name, char *trigger)
+{
+ struct p54_led_dev *led = &priv->leds[led_index];
+ int err;
+
+ if (led->registered)
+ return -EEXIST;
+
+ snprintf(led->name, sizeof(led->name), "p54-%s::%s",
+ wiphy_name(priv->hw->wiphy), name);
+ led->hw_dev = priv->hw;
+ led->index = led_index;
+ led->led_dev.name = led->name;
+ led->led_dev.default_trigger = trigger;
+ led->led_dev.brightness_set = p54_led_brightness_set;
+
+ err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev);
+ if (err)
+ printk(KERN_ERR "%s: Failed to register %s LED.\n",
+ wiphy_name(priv->hw->wiphy), name);
+ else
+ led->registered = 1;
+
+ return err;
+}
+
+int p54_init_leds(struct p54_common *priv)
+{
+ int err;
+
+ /*
+ * TODO:
+ * Figure out if the EEPROM contains some hints about the number
+ * of available/programmable LEDs of the device.
+ */
+
+ INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
+
+ err = p54_register_led(priv, 0, "assoc",
+ ieee80211_get_assoc_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 1, "tx",
+ ieee80211_get_tx_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 2, "rx",
+ ieee80211_get_rx_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_register_led(priv, 3, "radio",
+ ieee80211_get_radio_led_name(priv->hw));
+ if (err)
+ return err;
+
+ err = p54_set_leds(priv);
+ return err;
+}
+
+void p54_unregister_leds(struct p54_common *priv)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(priv->leds); i++) {
+ if (priv->leds[i].registered) {
+ priv->leds[i].registered = false;
+ priv->leds[i].toggled = 0;
+ led_classdev_unregister(&priv->leds[i].led_dev);
+ }
+ }
+
+ cancel_delayed_work_sync(&priv->led_work);
+}
diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h
new file mode 100644
index 00000000000..04b63ec80fa
--- /dev/null
+++ b/drivers/net/wireless/p54/lmac.h
@@ -0,0 +1,558 @@
+/*
+ * LMAC Interface specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007 - 2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ * Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef LMAC_H
+#define LMAC_H
+
+enum p54_control_frame_types {
+ P54_CONTROL_TYPE_SETUP = 0,
+ P54_CONTROL_TYPE_SCAN,
+ P54_CONTROL_TYPE_TRAP,
+ P54_CONTROL_TYPE_DCFINIT,
+ P54_CONTROL_TYPE_RX_KEYCACHE,
+ P54_CONTROL_TYPE_TIM,
+ P54_CONTROL_TYPE_PSM,
+ P54_CONTROL_TYPE_TXCANCEL,
+ P54_CONTROL_TYPE_TXDONE,
+ P54_CONTROL_TYPE_BURST,
+ P54_CONTROL_TYPE_STAT_READBACK,
+ P54_CONTROL_TYPE_BBP,
+ P54_CONTROL_TYPE_EEPROM_READBACK,
+ P54_CONTROL_TYPE_LED,
+ P54_CONTROL_TYPE_GPIO,
+ P54_CONTROL_TYPE_TIMER,
+ P54_CONTROL_TYPE_MODULATION,
+ P54_CONTROL_TYPE_SYNTH_CONFIG,
+ P54_CONTROL_TYPE_DETECTOR_VALUE,
+ P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+ P54_CONTROL_TYPE_CCE_QUIET,
+ P54_CONTROL_TYPE_PSM_STA_UNLOCK,
+ P54_CONTROL_TYPE_PCS,
+ P54_CONTROL_TYPE_BT_BALANCER = 28,
+ P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
+ P54_CONTROL_TYPE_ARPTABLE = 31,
+ P54_CONTROL_TYPE_BT_OPTIONS = 35,
+};
+
+#define P54_HDR_FLAG_CONTROL BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
+#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
+
+#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
+#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
+#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
+#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
+#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
+#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
+#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
+#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
+#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
+#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
+#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
+#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
+
+#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
+#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
+#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
+#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
+#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
+#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
+#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
+#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
+#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
+#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
+
+struct p54_hdr {
+ __le16 flags;
+ __le16 len;
+ __le32 req_id;
+ __le16 type; /* enum p54_control_frame_types */
+ u8 rts_tries;
+ u8 tries;
+ u8 data[0];
+} __packed;
+
+#define GET_REQ_ID(skb) \
+ (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id) \
+
+#define FREE_AFTER_TX(skb) \
+ ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
+#define IS_DATA_FRAME(skb) \
+ (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
+ flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
+
+#define GET_HW_QUEUE(skb) \
+ (((struct p54_tx_data *)((struct p54_hdr *) \
+ skb->data)->data)->hw_queue)
+
+/*
+ * shared interface ID definitions
+ * The interface ID is a unique identification of a specific interface.
+ * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015
+ */
+#define IF_ID_ISL36356A 0x0001 /* ISL36356A <-> Firmware */
+#define IF_ID_MVC 0x0003 /* MAC Virtual Coprocessor */
+#define IF_ID_DEBUG 0x0008 /* PolDebug Interface */
+#define IF_ID_PRODUCT 0x0009
+#define IF_ID_OEM 0x000a
+#define IF_ID_PCI3877 0x000b /* 3877 <-> Host PCI */
+#define IF_ID_ISL37704C 0x000c /* ISL37704C <-> Fw */
+#define IF_ID_ISL39000 0x000f /* ISL39000 <-> Fw */
+#define IF_ID_ISL39300A 0x0010 /* ISL39300A <-> Fw */
+#define IF_ID_ISL37700_UAP 0x0016 /* ISL37700 uAP Fw <-> Fw */
+#define IF_ID_ISL39000_UAP 0x0017 /* ISL39000 uAP Fw <-> Fw */
+#define IF_ID_LMAC 0x001a /* Interface exposed by LMAC */
+
+struct exp_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+ __le16 btm_compat;
+ __le16 top_compat;
+} __packed;
+
+struct dep_if {
+ __le16 role;
+ __le16 if_id;
+ __le16 variant;
+} __packed;
+
+/* driver <-> lmac definitions */
+struct p54_eeprom_lm86 {
+ union {
+ struct {
+ __le16 offset;
+ __le16 len;
+ u8 data[0];
+ } __packed v1;
+ struct {
+ __le32 offset;
+ __le16 len;
+ u8 magic2;
+ u8 pad;
+ u8 magic[4];
+ u8 data[0];
+ } __packed v2;
+ } __packed;
+} __packed;
+
+enum p54_rx_decrypt_status {
+ P54_DECRYPT_NONE = 0,
+ P54_DECRYPT_OK,
+ P54_DECRYPT_NOKEY,
+ P54_DECRYPT_NOMICHAEL,
+ P54_DECRYPT_NOCKIPMIC,
+ P54_DECRYPT_FAIL_WEP,
+ P54_DECRYPT_FAIL_TKIP,
+ P54_DECRYPT_FAIL_MICHAEL,
+ P54_DECRYPT_FAIL_CKIPKP,
+ P54_DECRYPT_FAIL_CKIPMIC,
+ P54_DECRYPT_FAIL_AESCCMP
+};
+
+struct p54_rx_data {
+ __le16 flags;
+ __le16 len;
+ __le16 freq;
+ u8 antenna;
+ u8 rate;
+ u8 rssi;
+ u8 quality;
+ u8 decrypt_status;
+ u8 rssi_raw;
+ __le32 tsf32;
+ __le32 unalloc0;
+ u8 align[0];
+} __packed;
+
+enum p54_trap_type {
+ P54_TRAP_SCAN = 0,
+ P54_TRAP_TIMER,
+ P54_TRAP_BEACON_TX,
+ P54_TRAP_FAA_RADIO_ON,
+ P54_TRAP_FAA_RADIO_OFF,
+ P54_TRAP_RADAR,
+ P54_TRAP_NO_BEACON,
+ P54_TRAP_TBTT,
+ P54_TRAP_SCO_ENTER,
+ P54_TRAP_SCO_EXIT
+};
+
+struct p54_trap {
+ __le16 event;
+ __le16 frequency;
+} __packed;
+
+enum p54_frame_sent_status {
+ P54_TX_OK = 0,
+ P54_TX_FAILED,
+ P54_TX_PSM,
+ P54_TX_PSM_CANCELLED = 4
+};
+
+struct p54_frame_sent {
+ u8 status;
+ u8 tries;
+ u8 ack_rssi;
+ u8 quality;
+ __le16 seq;
+ u8 antenna;
+ u8 padding;
+} __packed;
+
+enum p54_tx_data_crypt {
+ P54_CRYPTO_NONE = 0,
+ P54_CRYPTO_WEP,
+ P54_CRYPTO_TKIP,
+ P54_CRYPTO_TKIPMICHAEL,
+ P54_CRYPTO_CCX_WEPMIC,
+ P54_CRYPTO_CCX_KPMIC,
+ P54_CRYPTO_CCX_KP,
+ P54_CRYPTO_AESCCMP
+};
+
+enum p54_tx_data_queue {
+ P54_QUEUE_BEACON = 0,
+ P54_QUEUE_FWSCAN = 1,
+ P54_QUEUE_MGMT = 2,
+ P54_QUEUE_CAB = 3,
+ P54_QUEUE_DATA = 4,
+
+ P54_QUEUE_AC_NUM = 4,
+ P54_QUEUE_AC_VO = 4,
+ P54_QUEUE_AC_VI = 5,
+ P54_QUEUE_AC_BE = 6,
+ P54_QUEUE_AC_BK = 7,
+
+ /* keep last */
+ P54_QUEUE_NUM = 8,
+};
+
+#define IS_QOS_QUEUE(n) (n >= P54_QUEUE_DATA)
+
+struct p54_tx_data {
+ u8 rateset[8];
+ u8 rts_rate_idx;
+ u8 crypt_offset;
+ u8 key_type;
+ u8 key_len;
+ u8 key[16];
+ u8 hw_queue;
+ u8 backlog;
+ __le16 durations[4];
+ u8 tx_antenna;
+ union {
+ struct {
+ u8 cts_rate;
+ __le16 output_power;
+ } __packed longbow;
+ struct {
+ u8 output_power;
+ u8 cts_rate;
+ u8 unalloc;
+ } __packed normal;
+ } __packed;
+ u8 unalloc2[2];
+ u8 align[0];
+} __packed;
+
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
+#define P54_FILTER_TYPE_NONE 0
+#define P54_FILTER_TYPE_STATION BIT(0)
+#define P54_FILTER_TYPE_IBSS BIT(1)
+#define P54_FILTER_TYPE_AP BIT(2)
+#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
+#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
+#define P54_FILTER_TYPE_HIBERNATE BIT(5)
+#define P54_FILTER_TYPE_NOACK BIT(6)
+#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
+
+struct p54_setup_mac {
+ __le16 mac_mode;
+ u8 mac_addr[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u8 rx_antenna;
+ u8 rx_align;
+ union {
+ struct {
+ __le32 basic_rate_mask;
+ u8 rts_rates[8];
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 wakeup_timer;
+ __le16 unalloc0;
+ } __packed v1;
+ struct {
+ __le32 rx_addr;
+ __le16 max_rx;
+ __le16 rxhw;
+ __le16 timer;
+ __le16 truncate;
+ __le32 basic_rate_mask;
+ u8 sbss_offset;
+ u8 mcast_window;
+ u8 rx_rssi_threshold;
+ u8 rx_ed_threshold;
+ __le32 ref_clock;
+ __le16 lpf_bandwidth;
+ __le16 osc_start_delay;
+ } __packed v2;
+ } __packed;
+} __packed;
+
+#define P54_SETUP_V1_LEN 40
+#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
+
+#define P54_SCAN_EXIT BIT(0)
+#define P54_SCAN_TRAP BIT(1)
+#define P54_SCAN_ACTIVE BIT(2)
+#define P54_SCAN_FILTER BIT(3)
+
+struct p54_scan_head {
+ __le16 mode;
+ __le16 dwell;
+ u8 scan_params[20];
+ __le16 freq;
+} __packed;
+
+struct p54_pa_curve_data_sample {
+ u8 rf_power;
+ u8 pa_detector;
+ u8 data_barker;
+ u8 data_bpsk;
+ u8 data_qpsk;
+ u8 data_16qam;
+ u8 data_64qam;
+ u8 padding;
+} __packed;
+
+struct p54_scan_body {
+ u8 pa_points_per_curve;
+ u8 val_barker;
+ u8 val_bpsk;
+ u8 val_qpsk;
+ u8 val_16qam;
+ u8 val_64qam;
+ struct p54_pa_curve_data_sample curve_data[8];
+ u8 dup_bpsk;
+ u8 dup_qpsk;
+ u8 dup_16qam;
+ u8 dup_64qam;
+} __packed;
+
+/*
+ * Warning: Longbow's structures are bogus.
+ */
+struct p54_channel_output_limit_longbow {
+ __le16 rf_power_points[12];
+} __packed;
+
+struct p54_pa_curve_data_sample_longbow {
+ __le16 rf_power;
+ __le16 pa_detector;
+ struct {
+ __le16 data[4];
+ } points[3] __packed;
+} __packed;
+
+struct p54_scan_body_longbow {
+ struct p54_channel_output_limit_longbow power_limits;
+ struct p54_pa_curve_data_sample_longbow curve_data[8];
+ __le16 unkn[6]; /* maybe more power_limits or rate_mask */
+} __packed;
+
+union p54_scan_body_union {
+ struct p54_scan_body normal;
+ struct p54_scan_body_longbow longbow;
+} __packed;
+
+struct p54_scan_tail_rate {
+ __le32 basic_rate_mask;
+ u8 rts_rates[8];
+} __packed;
+
+struct p54_led {
+ __le16 flags;
+ __le16 mask[2];
+ __le16 delay[2];
+} __packed;
+
+struct p54_edcf {
+ u8 flags;
+ u8 slottime;
+ u8 sifs;
+ u8 eofpad;
+ struct p54_edcf_queue_param queue[8];
+ u8 mapping[4];
+ __le16 frameburst;
+ __le16 round_trip_delay;
+} __packed;
+
+struct p54_statistics {
+ __le32 rx_success;
+ __le32 rx_bad_fcs;
+ __le32 rx_abort;
+ __le32 rx_abort_phy;
+ __le32 rts_success;
+ __le32 rts_fail;
+ __le32 tsf32;
+ __le32 airtime;
+ __le32 noise;
+ __le32 sample_noise[8];
+ __le32 sample_cca;
+ __le32 sample_tx;
+} __packed;
+
+struct p54_xbow_synth {
+ __le16 magic1;
+ __le16 magic2;
+ __le16 freq;
+ u32 padding[5];
+} __packed;
+
+struct p54_timer {
+ __le32 interval;
+} __packed;
+
+struct p54_keycache {
+ u8 entry;
+ u8 key_id;
+ u8 mac[ETH_ALEN];
+ u8 padding[2];
+ u8 key_type;
+ u8 key_len;
+ u8 key[24];
+} __packed;
+
+struct p54_burst {
+ u8 flags;
+ u8 queue;
+ u8 backlog;
+ u8 pad;
+ __le16 durations[32];
+} __packed;
+
+struct p54_psm_interval {
+ __le16 interval;
+ __le16 periods;
+} __packed;
+
+#define P54_PSM_CAM 0
+#define P54_PSM BIT(0)
+#define P54_PSM_DTIM BIT(1)
+#define P54_PSM_MCBC BIT(2)
+#define P54_PSM_CHECKSUM BIT(3)
+#define P54_PSM_SKIP_MORE_DATA BIT(4)
+#define P54_PSM_BEACON_TIMEOUT BIT(5)
+#define P54_PSM_HFOSLEEP BIT(6)
+#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
+#define P54_PSM_LPIT BIT(8)
+#define P54_PSM_BF_UCAST_SKIP BIT(9)
+#define P54_PSM_BF_MCAST_SKIP BIT(10)
+
+struct p54_psm {
+ __le16 mode;
+ __le16 aid;
+ struct p54_psm_interval intervals[4];
+ u8 beacon_rssi_skip_max;
+ u8 rssi_delta_threshold;
+ u8 nr;
+ u8 exclude[1];
+} __packed;
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct p54_group_address_table {
+ __le16 filter_enable;
+ __le16 num_address;
+ u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
+} __packed;
+
+struct p54_txcancel {
+ __le32 req_id;
+} __packed;
+
+struct p54_sta_unlock {
+ u8 addr[ETH_ALEN];
+ u16 padding;
+} __packed;
+
+#define P54_TIM_CLEAR BIT(15)
+struct p54_tim {
+ u8 count;
+ u8 padding[3];
+ __le16 entry[8];
+} __packed;
+
+struct p54_cce_quiet {
+ __le32 period;
+} __packed;
+
+struct p54_bt_balancer {
+ __le16 prio_thresh;
+ __le16 acl_thresh;
+} __packed;
+
+struct p54_arp_table {
+ __le16 filter_enable;
+ u8 ipv4_addr[4];
+} __packed;
+
+/* LED control */
+int p54_set_leds(struct p54_common *priv);
+int p54_init_leds(struct p54_common *priv);
+void p54_unregister_leds(struct p54_common *priv);
+
+/* xmit functions */
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb);
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id);
+void p54_tx(struct p54_common *priv, struct sk_buff *skb);
+
+/* synth/phy configuration */
+int p54_init_xbow_synth(struct p54_common *priv);
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell);
+
+/* MAC */
+int p54_sta_unlock(struct p54_common *priv, u8 *addr);
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
+int p54_setup_mac(struct p54_common *priv);
+int p54_set_ps(struct p54_common *priv);
+int p54_fetch_statistics(struct p54_common *priv);
+
+/* e/v DCF setup */
+int p54_set_edcf(struct p54_common *priv);
+
+/* cryptographic engine */
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
+ u8 idx, u8 len, u8 *addr, u8* key);
+
+/* eeprom */
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+ u16 offset, u16 len);
+
+/* utility */
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie);
+
+#endif /* LMAC_H */
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
new file mode 100644
index 00000000000..955f6d7ec16
--- /dev/null
+++ b/drivers/net/wireless/p54/main.c
@@ -0,0 +1,637 @@
+/*
+ * mac80211 glue code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+ enum sta_notify_cmd notify_cmd,
+ struct ieee80211_sta *sta)
+{
+ struct p54_common *priv = dev->priv;
+ switch (notify_cmd) {
+ case STA_NOTIFY_ADD:
+ case STA_NOTIFY_REMOVE:
+ /*
+ * Notify the firmware that we don't want or we don't
+ * need to buffer frames for this station anymore.
+ */
+
+ p54_sta_unlock(priv, sta->addr);
+ break;
+ case STA_NOTIFY_AWAKE:
+ /* update the firmware's filter table */
+ p54_sta_unlock(priv, sta->addr);
+ break;
+ default:
+ break;
+ }
+}
+
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct p54_common *priv = dev->priv;
+
+ return p54_update_beacon_tim(priv, sta->aid, set);
+}
+
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
+{
+ struct ieee80211_mgmt *mgmt = (void *)skb->data;
+ u8 *pos, *end;
+
+ if (skb->len <= sizeof(mgmt))
+ return NULL;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = skb->data + skb->len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return NULL;
+
+ if (pos[0] == ie)
+ return pos;
+
+ pos += 2 + pos[1];
+ }
+ return NULL;
+}
+
+static int p54_beacon_format_ie_tim(struct sk_buff *skb)
+{
+ /*
+ * the good excuse for this mess is ... the firmware.
+ * The dummy TIM MUST be at the end of the beacon frame,
+ * because it'll be overwritten!
+ */
+ u8 *tim;
+ u8 dtim_len;
+ u8 dtim_period;
+ u8 *next;
+
+ tim = p54_find_ie(skb, WLAN_EID_TIM);
+ if (!tim)
+ return 0;
+
+ dtim_len = tim[1];
+ dtim_period = tim[3];
+ next = tim + 2 + dtim_len;
+
+ if (dtim_len < 3)
+ return -EINVAL;
+
+ memmove(tim, next, skb_tail_pointer(skb) - next);
+ tim = skb_tail_pointer(skb) - (dtim_len + 2);
+
+ /* add the dummy at the end */
+ tim[0] = WLAN_EID_TIM;
+ tim[1] = 3;
+ tim[2] = 0;
+ tim[3] = dtim_period;
+ tim[4] = 0;
+
+ if (dtim_len > 3)
+ skb_trim(skb, skb->len - (dtim_len - 3));
+
+ return 0;
+}
+
+static int p54_beacon_update(struct p54_common *priv,
+ struct ieee80211_vif *vif)
+{
+ struct sk_buff *beacon;
+ int ret;
+
+ beacon = ieee80211_beacon_get(priv->hw, vif);
+ if (!beacon)
+ return -ENOMEM;
+ ret = p54_beacon_format_ie_tim(beacon);
+ if (ret)
+ return ret;
+
+ /*
+ * During operation, the firmware takes care of beaconing.
+ * The driver only needs to upload a new beacon template, once
+ * the template was changed by the stack or userspace.
+ *
+ * LMAC API 3.2.2 also specifies that the driver does not need
+ * to cancel the old beacon template by hand, instead the firmware
+ * will release the previous one through the feedback mechanism.
+ */
+ WARN_ON(p54_tx_80211(priv->hw, beacon));
+ priv->tsf_high32 = 0;
+ priv->tsf_low32 = 0;
+
+ return 0;
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ mutex_lock(&priv->conf_mutex);
+ err = priv->open(dev);
+ if (err)
+ goto out;
+ P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
+ P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
+ P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
+ P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
+ err = p54_set_edcf(priv);
+ if (err)
+ goto out;
+
+ memset(priv->bssid, ~0, ETH_ALEN);
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ err = p54_setup_mac(priv);
+ if (err) {
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ goto out;
+ }
+
+ queue_delayed_work(dev->workqueue, &priv->work, 0);
+
+ priv->softled_state = 0;
+ err = p54_set_leds(priv);
+
+out:
+ mutex_unlock(&priv->conf_mutex);
+ return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ int i;
+
+ mutex_lock(&priv->conf_mutex);
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->softled_state = 0;
+ p54_set_leds(priv);
+
+ cancel_delayed_work_sync(&priv->work);
+
+ priv->stop(dev);
+ skb_queue_purge(&priv->tx_pending);
+ skb_queue_purge(&priv->tx_queue);
+ for (i = 0; i < P54_QUEUE_NUM; i++) {
+ priv->tx_stats[i].count = 0;
+ priv->tx_stats[i].len = 0;
+ }
+
+ priv->beacon_req_id = cpu_to_le32(0);
+ priv->tsf_high32 = priv->tsf_low32 = 0;
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (priv->mode != NL80211_IFTYPE_MONITOR) {
+ mutex_unlock(&priv->conf_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ priv->vif = conf->vif;
+
+ switch (conf->type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MESH_POINT:
+ priv->mode = conf->type;
+ break;
+ default:
+ mutex_unlock(&priv->conf_mutex);
+ return -EOPNOTSUPP;
+ }
+
+ memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+ p54_setup_mac(priv);
+ mutex_unlock(&priv->conf_mutex);
+ return 0;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ priv->vif = NULL;
+
+ /*
+ * LMAC API 3.2.2 states that any active beacon template must be
+ * canceled by the driver before attempting a mode transition.
+ */
+ if (le32_to_cpu(priv->beacon_req_id) != 0) {
+ p54_tx_cancel(priv, priv->beacon_req_id);
+ wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
+ }
+ priv->mode = NL80211_IFTYPE_MONITOR;
+ memset(priv->mac_addr, 0, ETH_ALEN);
+ memset(priv->bssid, 0, ETH_ALEN);
+ p54_setup_mac(priv);
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
+{
+ int ret = 0;
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_conf *conf = &dev->conf;
+
+ mutex_lock(&priv->conf_mutex);
+ if (changed & IEEE80211_CONF_CHANGE_POWER)
+ priv->output_power = conf->power_level << 2;
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+ ret = p54_scan(priv, P54_SCAN_EXIT, 0);
+ if (ret)
+ goto out;
+ }
+ if (changed & IEEE80211_CONF_CHANGE_PS) {
+ ret = p54_set_ps(priv);
+ if (ret)
+ goto out;
+ }
+
+out:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ int mc_count, struct dev_mc_list *mclist)
+{
+ struct p54_common *priv = dev->priv;
+
+ *total_flags &= FIF_PROMISC_IN_BSS |
+ FIF_OTHER_BSS;
+
+ priv->filter_flags = *total_flags;
+
+ if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
+ p54_setup_mac(priv);
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+{
+ struct p54_common *priv = dev->priv;
+ int ret;
+
+ mutex_lock(&priv->conf_mutex);
+ if ((params) && !(queue > 4)) {
+ P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
+ params->cw_min, params->cw_max, params->txop);
+ ret = p54_set_edcf(priv);
+ } else
+ ret = -EINVAL;
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static void p54_work(struct work_struct *work)
+{
+ struct p54_common *priv = container_of(work, struct p54_common,
+ work.work);
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ /*
+ * TODO: walk through tx_queue and do the following tasks
+ * 1. initiate bursts.
+ * 2. cancel stuck frames / reset the device if necessary.
+ */
+
+ p54_fetch_statistics(priv);
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+ struct ieee80211_low_level_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+
+ memcpy(stats, &priv->stats, sizeof(*stats));
+ return 0;
+}
+
+static int p54_get_tx_stats(struct ieee80211_hw *dev,
+ struct ieee80211_tx_queue_stats *stats)
+{
+ struct p54_common *priv = dev->priv;
+
+ memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
+ sizeof(stats[0]) * dev->queues);
+ return 0;
+}
+
+static void p54_bss_info_changed(struct ieee80211_hw *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *info,
+ u32 changed)
+{
+ struct p54_common *priv = dev->priv;
+
+ mutex_lock(&priv->conf_mutex);
+ if (changed & BSS_CHANGED_BSSID) {
+ memcpy(priv->bssid, info->bssid, ETH_ALEN);
+ p54_setup_mac(priv);
+ }
+
+ if (changed & BSS_CHANGED_BEACON) {
+ p54_scan(priv, P54_SCAN_EXIT, 0);
+ p54_setup_mac(priv);
+ p54_beacon_update(priv, vif);
+ p54_set_edcf(priv);
+ }
+
+ if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
+ priv->use_short_slot = info->use_short_slot;
+ p54_set_edcf(priv);
+ }
+ if (changed & BSS_CHANGED_BASIC_RATES) {
+ if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
+ priv->basic_rate_mask = (info->basic_rates << 4);
+ else
+ priv->basic_rate_mask = info->basic_rates;
+ p54_setup_mac(priv);
+ if (priv->fw_var >= 0x500)
+ p54_scan(priv, P54_SCAN_EXIT, 0);
+ }
+ if (changed & BSS_CHANGED_ASSOC) {
+ if (info->assoc) {
+ priv->aid = info->aid;
+ priv->wakeup_timer = info->beacon_int *
+ info->dtim_period * 5;
+ p54_setup_mac(priv);
+ } else {
+ priv->wakeup_timer = 500;
+ priv->aid = 0;
+ }
+ }
+
+ mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct p54_common *priv = dev->priv;
+ int slot, ret = 0;
+ u8 algo = 0;
+ u8 *addr = NULL;
+
+ if (modparam_nohwcrypt)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&priv->conf_mutex);
+ if (cmd == SET_KEY) {
+ switch (key->alg) {
+ case ALG_TKIP:
+ if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
+ BR_DESC_PRIV_CAP_TKIP))) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_TKIPMICHAEL;
+ break;
+ case ALG_WEP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_WEP;
+ break;
+ case ALG_CCMP:
+ if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ algo = P54_CRYPTO_AESCCMP;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+ slot = bitmap_find_free_region(priv->used_rxkeys,
+ priv->rx_keycache_size, 0);
+
+ if (slot < 0) {
+ /*
+ * The device supports the choosen algorithm, but the
+ * firmware does not provide enough key slots to store
+ * all of them.
+ * But encryption offload for outgoing frames is always
+ * possible, so we just pretend that the upload was
+ * successful and do the decryption in software.
+ */
+
+ /* mark the key as invalid. */
+ key->hw_key_idx = 0xff;
+ goto out_unlock;
+ }
+ } else {
+ slot = key->hw_key_idx;
+
+ if (slot == 0xff) {
+ /* This key was not uploaded into the rx key cache. */
+
+ goto out_unlock;
+ }
+
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ algo = 0;
+ }
+
+ if (sta)
+ addr = sta->addr;
+
+ ret = p54_upload_key(priv, algo, slot, key->keyidx,
+ key->keylen, addr, key->key);
+ if (ret) {
+ bitmap_release_region(priv->used_rxkeys, slot, 0);
+ ret = -EOPNOTSUPP;
+ goto out_unlock;
+ }
+
+ key->hw_key_idx = slot;
+
+out_unlock:
+ mutex_unlock(&priv->conf_mutex);
+ return ret;
+}
+
+static const struct ieee80211_ops p54_ops = {
+ .tx = p54_tx_80211,
+ .start = p54_start,
+ .stop = p54_stop,
+ .add_interface = p54_add_interface,
+ .remove_interface = p54_remove_interface,
+ .set_tim = p54_set_tim,
+ .sta_notify = p54_sta_notify,
+ .set_key = p54_set_key,
+ .config = p54_config,
+ .bss_info_changed = p54_bss_info_changed,
+ .configure_filter = p54_configure_filter,
+ .conf_tx = p54_conf_tx,
+ .get_stats = p54_get_stats,
+ .get_tx_stats = p54_get_tx_stats
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+ struct ieee80211_hw *dev;
+ struct p54_common *priv;
+
+ dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+ if (!dev)
+ return NULL;
+
+ priv = dev->priv;
+ priv->hw = dev;
+ priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->basic_rate_mask = 0x15f;
+ spin_lock_init(&priv->tx_stats_lock);
+ skb_queue_head_init(&priv->tx_queue);
+ skb_queue_head_init(&priv->tx_pending);
+ dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_BEACON_FILTER |
+ IEEE80211_HW_NOISE_DBM;
+
+ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_MESH_POINT);
+
+ dev->channel_change_time = 1000; /* TODO: find actual value */
+ priv->beacon_req_id = cpu_to_le32(0);
+ priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
+ priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
+ priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
+ priv->tx_stats[P54_QUEUE_CAB].limit = 3;
+ priv->tx_stats[P54_QUEUE_DATA].limit = 5;
+ dev->queues = 1;
+ priv->noise = -94;
+ /*
+ * We support at most 8 tries no matter which rate they're at,
+ * we cannot support max_rates * max_rate_tries as we set it
+ * here, but setting it correctly to 4/2 or so would limit us
+ * artificially if the RC algorithm wants just two rates, so
+ * let's say 4/7, we'll redistribute it at TX time, see the
+ * comments there.
+ */
+ dev->max_rates = 4;
+ dev->max_rate_tries = 7;
+ dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
+ sizeof(struct p54_tx_data);
+
+ mutex_init(&priv->conf_mutex);
+ mutex_init(&priv->eeprom_mutex);
+ init_completion(&priv->eeprom_comp);
+ init_completion(&priv->beacon_comp);
+ INIT_DELAYED_WORK(&priv->work, p54_work);
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
+{
+ struct p54_common *priv = dev->priv;
+ int err;
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ dev_err(pdev, "Cannot register device (%d).\n", err);
+ return err;
+ }
+
+#ifdef CONFIG_P54_LEDS
+ err = p54_init_leds(priv);
+ if (err)
+ return err;
+#endif /* CONFIG_P54_LEDS */
+
+ dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(p54_register_common);
+
+void p54_free_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+ unsigned int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ kfree(priv->band_table[i]);
+
+ kfree(priv->iq_autocal);
+ kfree(priv->output_limit);
+ kfree(priv->curve_data);
+ kfree(priv->used_rxkeys);
+ priv->iq_autocal = NULL;
+ priv->output_limit = NULL;
+ priv->curve_data = NULL;
+ priv->used_rxkeys = NULL;
+ ieee80211_free_hw(dev);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+void p54_unregister_common(struct ieee80211_hw *dev)
+{
+ struct p54_common *priv = dev->priv;
+
+#ifdef CONFIG_P54_LEDS
+ p54_unregister_leds(priv);
+#endif /* CONFIG_P54_LEDS */
+
+ ieee80211_unregister_hw(dev);
+ mutex_destroy(&priv->conf_mutex);
+ mutex_destroy(&priv->eeprom_mutex);
+}
+EXPORT_SYMBOL_GPL(p54_unregister_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index db3df947d8e..1afc39410e8 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -1,6 +1,3 @@
-#ifndef P54_H
-#define P54_H
-
/*
* Shared defines for all mac80211 Prism54 code
*
@@ -14,39 +11,78 @@
* published by the Free Software Foundation.
*/
+#ifndef P54_H
+#define P54_H
+
#ifdef CONFIG_P54_LEDS
#include <linux/leds.h>
#endif /* CONFIG_P54_LEDS */
-enum p54_control_frame_types {
- P54_CONTROL_TYPE_SETUP = 0,
- P54_CONTROL_TYPE_SCAN,
- P54_CONTROL_TYPE_TRAP,
- P54_CONTROL_TYPE_DCFINIT,
- P54_CONTROL_TYPE_RX_KEYCACHE,
- P54_CONTROL_TYPE_TIM,
- P54_CONTROL_TYPE_PSM,
- P54_CONTROL_TYPE_TXCANCEL,
- P54_CONTROL_TYPE_TXDONE,
- P54_CONTROL_TYPE_BURST,
- P54_CONTROL_TYPE_STAT_READBACK,
- P54_CONTROL_TYPE_BBP,
- P54_CONTROL_TYPE_EEPROM_READBACK,
- P54_CONTROL_TYPE_LED,
- P54_CONTROL_TYPE_GPIO,
- P54_CONTROL_TYPE_TIMER,
- P54_CONTROL_TYPE_MODULATION,
- P54_CONTROL_TYPE_SYNTH_CONFIG,
- P54_CONTROL_TYPE_DETECTOR_VALUE,
- P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
- P54_CONTROL_TYPE_CCE_QUIET,
- P54_CONTROL_TYPE_PSM_STA_UNLOCK,
- P54_CONTROL_TYPE_PCS,
- P54_CONTROL_TYPE_BT_BALANCER = 28,
- P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
- P54_CONTROL_TYPE_ARPTABLE = 31,
- P54_CONTROL_TYPE_BT_OPTIONS = 35
-};
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+#define BR_CODE_MIN 0x80000000
+#define BR_CODE_COMPONENT_ID 0x80000001
+#define BR_CODE_COMPONENT_VERSION 0x80000002
+#define BR_CODE_DEPENDENT_IF 0x80000003
+#define BR_CODE_EXPOSED_IF 0x80000004
+#define BR_CODE_DESCR 0x80000101
+#define BR_CODE_MAX 0x8FFFFFFF
+#define BR_CODE_END_OF_BRA 0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
+
+struct bootrec {
+ __le32 code;
+ __le32 len;
+ u32 data[10];
+} __packed;
+
+/* Interface role definitions */
+#define BR_INTERFACE_ROLE_SERVER 0x0000
+#define BR_INTERFACE_ROLE_CLIENT 0x8000
+
+#define BR_DESC_PRIV_CAP_WEP BIT(0)
+#define BR_DESC_PRIV_CAP_TKIP BIT(1)
+#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
+#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
+#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
+#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
+
+struct bootrec_desc {
+ __le16 modes;
+ __le16 flags;
+ __le32 rx_start;
+ __le32 rx_end;
+ u8 headroom;
+ u8 tailroom;
+ u8 tx_queues;
+ u8 tx_depth;
+ u8 privacy_caps;
+ u8 rx_keycache_size;
+ u8 time_size;
+ u8 padding;
+ u8 rates[16];
+ u8 padding2[4];
+ __le16 rx_mtu;
+} __packed;
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+struct bootrec_comp_id {
+ __le32 fw_variant;
+} __packed;
+
+struct bootrec_comp_ver {
+ char fw_version[24];
+} __packed;
+
+struct bootrec_end {
+ __le16 crc;
+ u8 padding[2];
+ u8 md5[16];
+} __packed;
/* provide 16 bytes for the transport back-end */
#define P54_TX_INFO_DATA_SIZE 16
@@ -55,34 +91,30 @@ enum p54_control_frame_types {
struct p54_tx_info {
u32 start_addr;
u32 end_addr;
- void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+ union {
+ void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+ struct {
+ u32 extra_len;
+ };
+ };
};
#define P54_MAX_CTRL_FRAME_LEN 0x1000
-#define P54_HDR_FLAG_CONTROL BIT(15)
-#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0))
-
-struct p54_hdr {
- __le16 flags;
- __le16 len;
- __le32 req_id;
- __le16 type; /* enum p54_control_frame_types */
- u8 rts_tries;
- u8 tries;
- u8 data[0];
-} __attribute__ ((packed));
-
-#define FREE_AFTER_TX(skb) \
- ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \
- flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
+do { \
+ queue.aifs = cpu_to_le16(ai_fs); \
+ queue.cwmin = cpu_to_le16(cw_min); \
+ queue.cwmax = cpu_to_le16(cw_max); \
+ queue.txop = cpu_to_le16(_txop); \
+} while (0)
struct p54_edcf_queue_param {
__le16 aifs;
__le16 cwmin;
__le16 cwmax;
__le16 txop;
-} __attribute__ ((packed));
+} __packed;
struct p54_rssi_linear_approximation {
s16 mul;
@@ -101,13 +133,6 @@ struct p54_cal_database {
#define EEPROM_READBACK_LEN 0x3fc
-#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
-
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
enum fw_state {
FW_STATE_OFF,
FW_STATE_BOOTING,
@@ -138,6 +163,7 @@ struct p54_common {
void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
int (*open)(struct ieee80211_hw *dev);
void (*stop)(struct ieee80211_hw *dev);
+ struct sk_buff_head tx_pending;
struct sk_buff_head tx_queue;
struct mutex conf_mutex;
@@ -156,6 +182,7 @@ struct p54_common {
/* (e)DCF / QOS state */
bool use_short_slot;
+ spinlock_t tx_stats_lock;
struct ieee80211_tx_queue_stats tx_stats[8];
struct p54_edcf_queue_param qos_params[8];
@@ -171,6 +198,7 @@ struct p54_common {
struct p54_cal_database *curve_data;
struct p54_cal_database *output_limit;
struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS];
+ struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
/* BBP/MAC state */
u8 mac_addr[ETH_ALEN];
@@ -181,7 +209,9 @@ struct p54_common {
u32 tsf_low32, tsf_high32;
u32 basic_rate_mask;
u16 aid;
- struct sk_buff *cached_beacon;
+ bool powersave_override;
+ __le32 beacon_req_id;
+ struct completion beacon_comp;
/* cryptographic engine information */
u8 privacy_caps;
@@ -202,15 +232,20 @@ struct p54_common {
/* eeprom handling */
void *eeprom;
struct completion eeprom_comp;
+ struct mutex eeprom_mutex;
};
+/* interfaces for the drivers */
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
int p54_read_eeprom(struct ieee80211_hw *dev);
+
struct ieee80211_hw *p54_init_common(size_t priv_data_len);
int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
void p54_free_common(struct ieee80211_hw *dev);
+void p54_unregister_common(struct ieee80211_hw *dev);
+
#endif /* P54_H */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
deleted file mode 100644
index 22ca122bd79..00000000000
--- a/drivers/net/wireless/p54/p54common.c
+++ /dev/null
@@ -1,2688 +0,0 @@
-/*
- * Common code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-
-#include <net/mac80211.h>
-#ifdef CONFIG_P54_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_P54_LEDS */
-
-#include "p54.h"
-#include "p54common.h"
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
-MODULE_DESCRIPTION("Softmac Prism54 common code");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54common");
-
-static struct ieee80211_rate p54_bgrates[] = {
- { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 60, .hw_value = 4, },
- { .bitrate = 90, .hw_value = 5, },
- { .bitrate = 120, .hw_value = 6, },
- { .bitrate = 180, .hw_value = 7, },
- { .bitrate = 240, .hw_value = 8, },
- { .bitrate = 360, .hw_value = 9, },
- { .bitrate = 480, .hw_value = 10, },
- { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_bgchannels[] = {
- { .center_freq = 2412, .hw_value = 1, },
- { .center_freq = 2417, .hw_value = 2, },
- { .center_freq = 2422, .hw_value = 3, },
- { .center_freq = 2427, .hw_value = 4, },
- { .center_freq = 2432, .hw_value = 5, },
- { .center_freq = 2437, .hw_value = 6, },
- { .center_freq = 2442, .hw_value = 7, },
- { .center_freq = 2447, .hw_value = 8, },
- { .center_freq = 2452, .hw_value = 9, },
- { .center_freq = 2457, .hw_value = 10, },
- { .center_freq = 2462, .hw_value = 11, },
- { .center_freq = 2467, .hw_value = 12, },
- { .center_freq = 2472, .hw_value = 13, },
- { .center_freq = 2484, .hw_value = 14, },
-};
-
-static struct ieee80211_supported_band band_2GHz = {
- .channels = p54_bgchannels,
- .n_channels = ARRAY_SIZE(p54_bgchannels),
- .bitrates = p54_bgrates,
- .n_bitrates = ARRAY_SIZE(p54_bgrates),
-};
-
-static struct ieee80211_rate p54_arates[] = {
- { .bitrate = 60, .hw_value = 4, },
- { .bitrate = 90, .hw_value = 5, },
- { .bitrate = 120, .hw_value = 6, },
- { .bitrate = 180, .hw_value = 7, },
- { .bitrate = 240, .hw_value = 8, },
- { .bitrate = 360, .hw_value = 9, },
- { .bitrate = 480, .hw_value = 10, },
- { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_channel p54_achannels[] = {
- { .center_freq = 4920 },
- { .center_freq = 4940 },
- { .center_freq = 4960 },
- { .center_freq = 4980 },
- { .center_freq = 5040 },
- { .center_freq = 5060 },
- { .center_freq = 5080 },
- { .center_freq = 5170 },
- { .center_freq = 5180 },
- { .center_freq = 5190 },
- { .center_freq = 5200 },
- { .center_freq = 5210 },
- { .center_freq = 5220 },
- { .center_freq = 5230 },
- { .center_freq = 5240 },
- { .center_freq = 5260 },
- { .center_freq = 5280 },
- { .center_freq = 5300 },
- { .center_freq = 5320 },
- { .center_freq = 5500 },
- { .center_freq = 5520 },
- { .center_freq = 5540 },
- { .center_freq = 5560 },
- { .center_freq = 5580 },
- { .center_freq = 5600 },
- { .center_freq = 5620 },
- { .center_freq = 5640 },
- { .center_freq = 5660 },
- { .center_freq = 5680 },
- { .center_freq = 5700 },
- { .center_freq = 5745 },
- { .center_freq = 5765 },
- { .center_freq = 5785 },
- { .center_freq = 5805 },
- { .center_freq = 5825 },
-};
-
-static struct ieee80211_supported_band band_5GHz = {
- .channels = p54_achannels,
- .n_channels = ARRAY_SIZE(p54_achannels),
- .bitrates = p54_arates,
- .n_bitrates = ARRAY_SIZE(p54_arates),
-};
-
-int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
-{
- struct p54_common *priv = dev->priv;
- struct bootrec_exp_if *exp_if;
- struct bootrec *bootrec;
- u32 *data = (u32 *)fw->data;
- u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
- u8 *fw_version = NULL;
- size_t len;
- int i;
- int maxlen;
-
- if (priv->rx_start)
- return 0;
-
- while (data < end_data && *data)
- data++;
-
- while (data < end_data && !*data)
- data++;
-
- bootrec = (struct bootrec *) data;
-
- while (bootrec->data <= end_data &&
- (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
- u32 code = le32_to_cpu(bootrec->code);
- switch (code) {
- case BR_CODE_COMPONENT_ID:
- priv->fw_interface = be32_to_cpup((__be32 *)
- bootrec->data);
- switch (priv->fw_interface) {
- case FW_LM86:
- case FW_LM20:
- case FW_LM87: {
- char *iftype = (char *)bootrec->data;
- printk(KERN_INFO "%s: p54 detected a LM%c%c "
- "firmware\n",
- wiphy_name(dev->wiphy),
- iftype[2], iftype[3]);
- break;
- }
- case FW_FMAC:
- default:
- printk(KERN_ERR "%s: unsupported firmware\n",
- wiphy_name(dev->wiphy));
- return -ENODEV;
- }
- break;
- case BR_CODE_COMPONENT_VERSION:
- /* 24 bytes should be enough for all firmwares */
- if (strnlen((unsigned char*)bootrec->data, 24) < 24)
- fw_version = (unsigned char*)bootrec->data;
- break;
- case BR_CODE_DESCR: {
- struct bootrec_desc *desc =
- (struct bootrec_desc *)bootrec->data;
- priv->rx_start = le32_to_cpu(desc->rx_start);
- /* FIXME add sanity checking */
- priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
- priv->headroom = desc->headroom;
- priv->tailroom = desc->tailroom;
- priv->privacy_caps = desc->privacy_caps;
- priv->rx_keycache_size = desc->rx_keycache_size;
- if (le32_to_cpu(bootrec->len) == 11)
- priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
- else
- priv->rx_mtu = (size_t)
- 0x620 - priv->tx_hdr_len;
- maxlen = priv->tx_hdr_len + /* USB devices */
- sizeof(struct p54_rx_data) +
- 4 + /* rx alignment */
- IEEE80211_MAX_FRAG_THRESHOLD;
- if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
- printk(KERN_INFO "p54: rx_mtu reduced from %d "
- "to %d\n", priv->rx_mtu,
- maxlen);
- priv->rx_mtu = maxlen;
- }
- break;
- }
- case BR_CODE_EXPOSED_IF:
- exp_if = (struct bootrec_exp_if *) bootrec->data;
- for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
- if (exp_if[i].if_id == cpu_to_le16(0x1a))
- priv->fw_var = le16_to_cpu(exp_if[i].variant);
- break;
- case BR_CODE_DEPENDENT_IF:
- break;
- case BR_CODE_END_OF_BRA:
- case LEGACY_BR_CODE_END_OF_BRA:
- end_data = NULL;
- break;
- default:
- break;
- }
- bootrec = (struct bootrec *)&bootrec->data[len];
- }
-
- if (fw_version)
- printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n",
- wiphy_name(dev->wiphy), fw_version,
- priv->fw_var >> 8, priv->fw_var & 0xff);
-
- if (priv->fw_var < 0x500)
- printk(KERN_INFO "%s: you are using an obsolete firmware. "
- "visit http://wireless.kernel.org/en/users/Drivers/p54 "
- "and grab one for \"kernel >= 2.6.28\"!\n",
- wiphy_name(dev->wiphy));
-
- if (priv->fw_var >= 0x300) {
- /* Firmware supports QoS, use it! */
- priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
- priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
- priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
- priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
- dev->queues = P54_QUEUE_AC_NUM;
- }
-
- if (!modparam_nohwcrypt) {
- printk(KERN_INFO "%s: cryptographic accelerator "
- "WEP:%s, TKIP:%s, CCMP:%s\n",
- wiphy_name(dev->wiphy),
- (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" :
- "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP |
- BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no",
- (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ?
- "YES" : "no");
-
- if (priv->rx_keycache_size) {
- /*
- * NOTE:
- *
- * The firmware provides at most 255 (0 - 254) slots
- * for keys which are then used to offload decryption.
- * As a result the 255 entry (aka 0xff) can be used
- * safely by the driver to mark keys that didn't fit
- * into the full cache. This trick saves us from
- * keeping a extra list for uploaded keys.
- */
-
- priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
- priv->rx_keycache_size), GFP_KERNEL);
-
- if (!priv->used_rxkeys)
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(p54_parse_firmware);
-
-static int p54_convert_rev0(struct ieee80211_hw *dev,
- struct pda_pa_curve_data *curve_data)
-{
- struct p54_common *priv = dev->priv;
- struct p54_pa_curve_data_sample *dst;
- struct pda_pa_curve_data_sample_rev0 *src;
- size_t cd_len = sizeof(*curve_data) +
- (curve_data->points_per_channel*sizeof(*dst) + 2) *
- curve_data->channels;
- unsigned int i, j;
- void *source, *target;
-
- priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
- GFP_KERNEL);
- if (!priv->curve_data)
- return -ENOMEM;
-
- priv->curve_data->entries = curve_data->channels;
- priv->curve_data->entry_size = sizeof(__le16) +
- sizeof(*dst) * curve_data->points_per_channel;
- priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
- priv->curve_data->len = cd_len;
- memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
- source = curve_data->data;
- target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
- for (i = 0; i < curve_data->channels; i++) {
- __le16 *freq = source;
- source += sizeof(__le16);
- *((__le16 *)target) = *freq;
- target += sizeof(__le16);
- for (j = 0; j < curve_data->points_per_channel; j++) {
- dst = target;
- src = source;
-
- dst->rf_power = src->rf_power;
- dst->pa_detector = src->pa_detector;
- dst->data_64qam = src->pcv;
- /* "invent" the points for the other modulations */
-#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
- dst->data_16qam = SUB(src->pcv, 12);
- dst->data_qpsk = SUB(dst->data_16qam, 12);
- dst->data_bpsk = SUB(dst->data_qpsk, 12);
- dst->data_barker = SUB(dst->data_bpsk, 14);
-#undef SUB
- target += sizeof(*dst);
- source += sizeof(*src);
- }
- }
-
- return 0;
-}
-
-static int p54_convert_rev1(struct ieee80211_hw *dev,
- struct pda_pa_curve_data *curve_data)
-{
- struct p54_common *priv = dev->priv;
- struct p54_pa_curve_data_sample *dst;
- struct pda_pa_curve_data_sample_rev1 *src;
- size_t cd_len = sizeof(*curve_data) +
- (curve_data->points_per_channel*sizeof(*dst) + 2) *
- curve_data->channels;
- unsigned int i, j;
- void *source, *target;
-
- priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
- GFP_KERNEL);
- if (!priv->curve_data)
- return -ENOMEM;
-
- priv->curve_data->entries = curve_data->channels;
- priv->curve_data->entry_size = sizeof(__le16) +
- sizeof(*dst) * curve_data->points_per_channel;
- priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
- priv->curve_data->len = cd_len;
- memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
- source = curve_data->data;
- target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
- for (i = 0; i < curve_data->channels; i++) {
- __le16 *freq = source;
- source += sizeof(__le16);
- *((__le16 *)target) = *freq;
- target += sizeof(__le16);
- for (j = 0; j < curve_data->points_per_channel; j++) {
- memcpy(target, source, sizeof(*src));
-
- target += sizeof(*dst);
- source += sizeof(*src);
- }
- source++;
- }
-
- return 0;
-}
-
-static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2",
- "Frisbee", "Xbow", "Longbow", "NULL", "NULL" };
-static int p54_init_xbow_synth(struct ieee80211_hw *dev);
-
-static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
- u16 type)
-{
- struct p54_common *priv = dev->priv;
- int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
- int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
- int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
- int i;
-
- if (len != (entry_size * num_entries)) {
- printk(KERN_ERR "%s: unknown rssi calibration data packing "
- " type:(%x) len:%d.\n",
- wiphy_name(dev->wiphy), type, len);
-
- print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
- data, len);
-
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
- return;
- }
-
- for (i = 0; i < num_entries; i++) {
- struct pda_rssi_cal_entry *cal = data +
- (offset + i * entry_size);
- priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
- priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
- }
-}
-
-static void p54_parse_default_country(struct ieee80211_hw *dev,
- void *data, int len)
-{
- struct pda_country *country;
-
- if (len != sizeof(*country)) {
- printk(KERN_ERR "%s: found possible invalid default country "
- "eeprom entry. (entry size: %d)\n",
- wiphy_name(dev->wiphy), len);
-
- print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
- data, len);
-
- printk(KERN_ERR "%s: please report this issue.\n",
- wiphy_name(dev->wiphy));
- return;
- }
-
- country = (struct pda_country *) data;
- if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
- regulatory_hint(dev->wiphy, country->alpha2);
- else {
- /* TODO:
- * write a shared/common function that converts
- * "Regulatory domain codes" (802.11-2007 14.8.2.2)
- * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
- */
- }
-}
-
-static int p54_convert_output_limits(struct ieee80211_hw *dev,
- u8 *data, size_t len)
-{
- struct p54_common *priv = dev->priv;
-
- if (len < 2)
- return -EINVAL;
-
- if (data[0] != 0) {
- printk(KERN_ERR "%s: unknown output power db revision:%x\n",
- wiphy_name(dev->wiphy), data[0]);
- return -EINVAL;
- }
-
- if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
- return -EINVAL;
-
- priv->output_limit = kmalloc(data[1] *
- sizeof(struct pda_channel_output_limit) +
- sizeof(*priv->output_limit), GFP_KERNEL);
-
- if (!priv->output_limit)
- return -ENOMEM;
-
- priv->output_limit->offset = 0;
- priv->output_limit->entries = data[1];
- priv->output_limit->entry_size =
- sizeof(struct pda_channel_output_limit);
- priv->output_limit->len = priv->output_limit->entry_size *
- priv->output_limit->entries +
- priv->output_limit->offset;
-
- memcpy(priv->output_limit->data, &data[2],
- data[1] * sizeof(struct pda_channel_output_limit));
-
- return 0;
-}
-
-static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
- size_t total_len)
-{
- struct p54_cal_database *dst;
- size_t payload_len, entries, entry_size, offset;
-
- payload_len = le16_to_cpu(src->len);
- entries = le16_to_cpu(src->entries);
- entry_size = le16_to_cpu(src->entry_size);
- offset = le16_to_cpu(src->offset);
- if (((entries * entry_size + offset) != payload_len) ||
- (payload_len + sizeof(*src) != total_len))
- return NULL;
-
- dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
- if (!dst)
- return NULL;
-
- dst->entries = entries;
- dst->entry_size = entry_size;
- dst->offset = offset;
- dst->len = payload_len;
-
- memcpy(dst->data, src->data, payload_len);
- return dst;
-}
-
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
-{
- struct p54_common *priv = dev->priv;
- struct eeprom_pda_wrap *wrap = NULL;
- struct pda_entry *entry;
- unsigned int data_len, entry_len;
- void *tmp;
- int err;
- u8 *end = (u8 *)eeprom + len;
- u16 synth = 0;
-
- wrap = (struct eeprom_pda_wrap *) eeprom;
- entry = (void *)wrap->data + le16_to_cpu(wrap->len);
-
- /* verify that at least the entry length/code fits */
- while ((u8 *)entry <= end - sizeof(*entry)) {
- entry_len = le16_to_cpu(entry->len);
- data_len = ((entry_len - 1) << 1);
-
- /* abort if entry exceeds whole structure */
- if ((u8 *)entry + sizeof(*entry) + data_len > end)
- break;
-
- switch (le16_to_cpu(entry->code)) {
- case PDR_MAC_ADDRESS:
- if (data_len != ETH_ALEN)
- break;
- SET_IEEE80211_PERM_ADDR(dev, entry->data);
- break;
- case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
- if (priv->output_limit)
- break;
- err = p54_convert_output_limits(dev, entry->data,
- data_len);
- if (err)
- goto err;
- break;
- case PDR_PRISM_PA_CAL_CURVE_DATA: {
- struct pda_pa_curve_data *curve_data =
- (struct pda_pa_curve_data *)entry->data;
- if (data_len < sizeof(*curve_data)) {
- err = -EINVAL;
- goto err;
- }
-
- switch (curve_data->cal_method_rev) {
- case 0:
- err = p54_convert_rev0(dev, curve_data);
- break;
- case 1:
- err = p54_convert_rev1(dev, curve_data);
- break;
- default:
- printk(KERN_ERR "%s: unknown curve data "
- "revision %d\n",
- wiphy_name(dev->wiphy),
- curve_data->cal_method_rev);
- err = -ENODEV;
- break;
- }
- if (err)
- goto err;
- }
- break;
- case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
- priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
- if (!priv->iq_autocal) {
- err = -ENOMEM;
- goto err;
- }
-
- memcpy(priv->iq_autocal, entry->data, data_len);
- priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
- break;
- case PDR_DEFAULT_COUNTRY:
- p54_parse_default_country(dev, entry->data, data_len);
- break;
- case PDR_INTERFACE_LIST:
- tmp = entry->data;
- while ((u8 *)tmp < entry->data + data_len) {
- struct bootrec_exp_if *exp_if = tmp;
- if (le16_to_cpu(exp_if->if_id) == 0xf)
- synth = le16_to_cpu(exp_if->variant);
- tmp += sizeof(struct bootrec_exp_if);
- }
- break;
- case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
- if (data_len < 2)
- break;
- priv->version = *(u8 *)(entry->data + 1);
- break;
- case PDR_RSSI_LINEAR_APPROXIMATION:
- case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
- case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
- p54_parse_rssical(dev, entry->data, data_len,
- le16_to_cpu(entry->code));
- break;
- case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
- __le16 *src = (void *) entry->data;
- s16 *dst = (void *) &priv->rssical_db;
- int i;
-
- if (data_len != sizeof(priv->rssical_db)) {
- err = -EINVAL;
- goto err;
- }
- for (i = 0; i < sizeof(priv->rssical_db) /
- sizeof(*src); i++)
- *(dst++) = (s16) le16_to_cpu(*(src++));
- }
- break;
- case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
- struct pda_custom_wrapper *pda = (void *) entry->data;
- if (priv->output_limit || data_len < sizeof(*pda))
- break;
- priv->output_limit = p54_convert_db(pda, data_len);
- }
- break;
- case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
- struct pda_custom_wrapper *pda = (void *) entry->data;
- if (priv->curve_data || data_len < sizeof(*pda))
- break;
- priv->curve_data = p54_convert_db(pda, data_len);
- }
- break;
- case PDR_END:
- /* make it overrun */
- entry_len = len;
- break;
- case PDR_MANUFACTURING_PART_NUMBER:
- case PDR_PDA_VERSION:
- case PDR_NIC_SERIAL_NUMBER:
- case PDR_REGULATORY_DOMAIN_LIST:
- case PDR_TEMPERATURE_TYPE:
- case PDR_PRISM_PCI_IDENTIFIER:
- case PDR_COUNTRY_INFORMATION:
- case PDR_OEM_NAME:
- case PDR_PRODUCT_NAME:
- case PDR_UTF8_OEM_NAME:
- case PDR_UTF8_PRODUCT_NAME:
- case PDR_COUNTRY_LIST:
- case PDR_ANTENNA_GAIN:
- case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA:
- case PDR_REGULATORY_POWER_LIMITS:
- case PDR_RADIATED_TRANSMISSION_CORRECTION:
- case PDR_PRISM_TX_IQ_CALIBRATION:
- case PDR_BASEBAND_REGISTERS:
- case PDR_PER_CHANNEL_BASEBAND_REGISTERS:
- break;
- default:
- printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n",
- wiphy_name(dev->wiphy),
- le16_to_cpu(entry->code));
- break;
- }
-
- entry = (void *)entry + (entry_len + 1)*2;
- }
-
- if (!synth || !priv->iq_autocal || !priv->output_limit ||
- !priv->curve_data) {
- printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
- wiphy_name(dev->wiphy));
- err = -EINVAL;
- goto err;
- }
-
- priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
- if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
- p54_init_xbow_synth(dev);
- if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz;
- if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
- dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz;
- if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
- priv->rx_diversity_mask = 3;
- if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
- priv->tx_diversity_mask = 3;
-
- if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
- u8 perm_addr[ETH_ALEN];
-
- printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
- wiphy_name(dev->wiphy));
- random_ether_addr(perm_addr);
- SET_IEEE80211_PERM_ADDR(dev, perm_addr);
- }
-
- printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
- wiphy_name(dev->wiphy),
- dev->wiphy->perm_addr,
- priv->version, p54_rf_chips[priv->rxhw]);
-
- return 0;
-
- err:
- if (priv->iq_autocal) {
- kfree(priv->iq_autocal);
- priv->iq_autocal = NULL;
- }
-
- if (priv->output_limit) {
- kfree(priv->output_limit);
- priv->output_limit = NULL;
- }
-
- if (priv->curve_data) {
- kfree(priv->curve_data);
- priv->curve_data = NULL;
- }
-
- printk(KERN_ERR "%s: eeprom parse failed!\n",
- wiphy_name(dev->wiphy));
- return err;
-}
-EXPORT_SYMBOL_GPL(p54_parse_eeprom);
-
-static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
-{
- struct p54_common *priv = dev->priv;
- int band = dev->conf.channel->band;
-
- if (priv->rxhw != PDR_SYNTH_FRONTEND_LONGBOW)
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
- else
- /*
- * TODO: find the correct formula
- */
- return ((rssi * priv->rssical_db[band].mul) / 64 +
- priv->rssical_db[band].add) / 4;
-}
-
-static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
- struct ieee80211_rx_status rx_status = {0};
- u16 freq = le16_to_cpu(hdr->freq);
- size_t header_len = sizeof(*hdr);
- u32 tsf32;
- u8 rate = hdr->rate & 0xf;
-
- /*
- * If the device is in a unspecified state we have to
- * ignore all data frames. Else we could end up with a
- * nasty crash.
- */
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return 0;
-
- if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) {
- return 0;
- }
-
- if (hdr->decrypt_status == P54_DECRYPT_OK)
- rx_status.flag |= RX_FLAG_DECRYPTED;
- if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
- (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
- rx_status.flag |= RX_FLAG_MMIC_ERROR;
-
- rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi);
- rx_status.noise = priv->noise;
- if (hdr->rate & 0x10)
- rx_status.flag |= RX_FLAG_SHORTPRE;
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
- rx_status.rate_idx = (rate < 4) ? 0 : rate - 4;
- else
- rx_status.rate_idx = rate;
-
- rx_status.freq = freq;
- rx_status.band = dev->conf.channel->band;
- rx_status.antenna = hdr->antenna;
-
- tsf32 = le32_to_cpu(hdr->tsf32);
- if (tsf32 < priv->tsf_low32)
- priv->tsf_high32++;
- rx_status.mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
- priv->tsf_low32 = tsf32;
-
- rx_status.flag |= RX_FLAG_TSFT;
-
- if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
- header_len += hdr->align[0];
-
- skb_pull(skb, header_len);
- skb_trim(skb, le16_to_cpu(hdr->len));
-
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
-
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_STATISTICS_UPDATE));
-
- return -1;
-}
-
-static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int i;
-
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- for (i = 0; i < dev->queues; i++)
- if (priv->tx_stats[i + P54_QUEUE_DATA].len <
- priv->tx_stats[i + P54_QUEUE_DATA].limit)
- ieee80211_wake_queue(dev, i);
-}
-
-void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct ieee80211_tx_info *info;
- struct p54_tx_info *range;
- unsigned long flags;
-
- if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue)))
- return;
-
- /*
- * don't try to free an already unlinked skb
- */
- if (unlikely((!skb->next) || (!skb->prev)))
- return;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- info = IEEE80211_SKB_CB(skb);
- range = (void *)info->rate_driver_data;
- if (skb->prev != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(skb->prev);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
- if (skb->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(skb->next);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
- __skb_unlink(skb, &priv->tx_queue);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- dev_kfree_skb_any(skb);
- p54_wake_free_queues(dev);
-}
-EXPORT_SYMBOL_GPL(p54_free_skb);
-
-static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
- __le32 req_id)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- entry = priv->tx_queue.next;
- while (entry != (struct sk_buff *)&priv->tx_queue) {
- struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
-
- if (hdr->req_id == req_id) {
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return entry;
- }
- entry = entry->next;
- }
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return NULL;
-}
-
-static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
- struct sk_buff *entry;
- u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
- struct p54_tx_info *range = NULL;
- unsigned long flags;
- int count, idx;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
- entry = (struct sk_buff *) priv->tx_queue.next;
- while (entry != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
- struct p54_hdr *entry_hdr;
- struct p54_tx_data *entry_data;
- unsigned int pad = 0, frame_len;
-
- range = (void *)info->rate_driver_data;
- if (range->start_addr != addr) {
- entry = entry->next;
- continue;
- }
-
- if (entry->next != (struct sk_buff *)&priv->tx_queue) {
- struct ieee80211_tx_info *ni;
- struct p54_tx_info *mr;
-
- ni = IEEE80211_SKB_CB(entry->next);
- mr = (struct p54_tx_info *)ni->rate_driver_data;
- }
-
- __skb_unlink(entry, &priv->tx_queue);
-
- frame_len = entry->len;
- entry_hdr = (struct p54_hdr *) entry->data;
- entry_data = (struct p54_tx_data *) entry_hdr->data;
- if (priv->tx_stats[entry_data->hw_queue].len)
- priv->tx_stats[entry_data->hw_queue].len--;
- priv->stats.dot11ACKFailureCount += payload->tries - 1;
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
- /*
- * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
- * generated by the driver. Therefore tx_status is bogus
- * and we don't want to confuse the mac80211 stack.
- */
- if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
- if (entry_data->hw_queue == P54_QUEUE_BEACON)
- priv->cached_beacon = NULL;
-
- kfree_skb(entry);
- goto out;
- }
-
- /*
- * Clear manually, ieee80211_tx_info_clear_status would
- * clear the counts too and we need them.
- */
- memset(&info->status.ampdu_ack_len, 0,
- sizeof(struct ieee80211_tx_info) -
- offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
- BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
- status.ampdu_ack_len) != 23);
-
- if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
- pad = entry_data->align[0];
-
- /* walk through the rates array and adjust the counts */
- count = payload->tries;
- for (idx = 0; idx < 4; idx++) {
- if (count >= info->status.rates[idx].count) {
- count -= info->status.rates[idx].count;
- } else if (count > 0) {
- info->status.rates[idx].count = count;
- count = 0;
- } else {
- info->status.rates[idx].idx = -1;
- info->status.rates[idx].count = 0;
- }
- }
-
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (!payload->status))
- info->flags |= IEEE80211_TX_STAT_ACK;
- if (payload->status & P54_TX_PSM_CANCELLED)
- info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- info->status.ack_signal = p54_rssi_to_dbm(dev,
- (int)payload->ack_rssi);
-
- /* Undo all changes to the frame. */
- switch (entry_data->key_type) {
- case P54_CRYPTO_TKIPMICHAEL: {
- u8 *iv = (u8 *)(entry_data->align + pad +
- entry_data->crypt_offset);
-
- /* Restore the original TKIP IV. */
- iv[2] = iv[0];
- iv[0] = iv[1];
- iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
-
- frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
- break;
- }
- case P54_CRYPTO_AESCCMP:
- frame_len -= 8; /* remove CCMP_MIC */
- break;
- case P54_CRYPTO_WEP:
- frame_len -= 4; /* remove WEP_ICV */
- break;
- }
- skb_trim(entry, frame_len);
- skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
- ieee80211_tx_status_irqsafe(dev, entry);
- goto out;
- }
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
-out:
- p54_wake_free_queues(dev);
-}
-
-static void p54_rx_eeprom_readback(struct ieee80211_hw *dev,
- struct sk_buff *skb)
-{
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
- struct p54_common *priv = dev->priv;
-
- if (!priv->eeprom)
- return ;
-
- if (priv->fw_var >= 0x509) {
- memcpy(priv->eeprom, eeprom->v2.data,
- le16_to_cpu(eeprom->v2.len));
- } else {
- memcpy(priv->eeprom, eeprom->v1.data,
- le16_to_cpu(eeprom->v1.len));
- }
-
- complete(&priv->eeprom_comp);
-}
-
-static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
- u32 tsf32;
-
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return ;
-
- tsf32 = le32_to_cpu(stats->tsf32);
- if (tsf32 < priv->tsf_low32)
- priv->tsf_high32++;
- priv->tsf_low32 = tsf32;
-
- priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
- priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
- priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
-
- priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise));
-
- p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id));
-}
-
-static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
- struct p54_trap *trap = (struct p54_trap *) hdr->data;
- u16 event = le16_to_cpu(trap->event);
- u16 freq = le16_to_cpu(trap->frequency);
-
- switch (event) {
- case P54_TRAP_BEACON_TX:
- break;
- case P54_TRAP_RADAR:
- printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
- wiphy_name(dev->wiphy), freq);
- break;
- case P54_TRAP_NO_BEACON:
- if (priv->vif)
- ieee80211_beacon_loss(priv->vif);
- break;
- case P54_TRAP_SCAN:
- break;
- case P54_TRAP_TBTT:
- break;
- case P54_TRAP_TIMER:
- break;
- default:
- printk(KERN_INFO "%s: received event:%x freq:%d\n",
- wiphy_name(dev->wiphy), event, freq);
- break;
- }
-}
-
-static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-
- switch (le16_to_cpu(hdr->type)) {
- case P54_CONTROL_TYPE_TXDONE:
- p54_rx_frame_sent(dev, skb);
- break;
- case P54_CONTROL_TYPE_TRAP:
- p54_rx_trap(dev, skb);
- break;
- case P54_CONTROL_TYPE_BBP:
- break;
- case P54_CONTROL_TYPE_STAT_READBACK:
- p54_rx_stats(dev, skb);
- break;
- case P54_CONTROL_TYPE_EEPROM_READBACK:
- p54_rx_eeprom_readback(dev, skb);
- break;
- default:
- printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
- wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
- break;
- }
-
- return 0;
-}
-
-/* returns zero if skb can be reused */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- u16 type = le16_to_cpu(*((__le16 *)skb->data));
-
- if (type & P54_HDR_FLAG_CONTROL)
- return p54_rx_control(dev, skb);
- else
- return p54_rx_data(dev, skb);
-}
-EXPORT_SYMBOL_GPL(p54_rx);
-
-/*
- * So, the firmware is somewhat stupid and doesn't know what places in its
- * memory incoming data should go to. By poking around in the firmware, we
- * can find some unused memory to upload our packets to. However, data that we
- * want the card to TX needs to stay intact until the card has told us that
- * it is done with it. This function finds empty places we can upload to and
- * marks allocated areas as reserved if necessary. p54_rx_frame_sent or
- * p54_free_skb frees allocated areas.
- */
-static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct p54_hdr *data, u32 len)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *entry;
- struct sk_buff *target_skb = NULL;
- struct ieee80211_tx_info *info;
- struct p54_tx_info *range;
- u32 last_addr = priv->rx_start;
- u32 largest_hole = 0;
- u32 target_addr = priv->rx_start;
- unsigned long flags;
- unsigned int left;
- len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;
-
- if (!skb)
- return -EINVAL;
-
- spin_lock_irqsave(&priv->tx_queue.lock, flags);
-
- left = skb_queue_len(&priv->tx_queue);
- if (unlikely(left >= 28)) {
- /*
- * The tx_queue is nearly full!
- * We have throttle normal data traffic, because we must
- * have a few spare slots for control frames left.
- */
- ieee80211_stop_queues(dev);
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_TX_TIMEOUT));
-
- if (unlikely(left == 32)) {
- /*
- * The tx_queue is now really full.
- *
- * TODO: check if the device has crashed and reset it.
- */
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- return -ENOSPC;
- }
- }
-
- entry = priv->tx_queue.next;
- while (left--) {
- u32 hole_size;
- info = IEEE80211_SKB_CB(entry);
- range = (void *)info->rate_driver_data;
- hole_size = range->start_addr - last_addr;
- if (!target_skb && hole_size >= len) {
- target_skb = entry->prev;
- hole_size -= len;
- target_addr = last_addr;
- }
- largest_hole = max(largest_hole, hole_size);
- last_addr = range->end_addr;
- entry = entry->next;
- }
- if (!target_skb && priv->rx_end - last_addr >= len) {
- target_skb = priv->tx_queue.prev;
- largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
- if (!skb_queue_empty(&priv->tx_queue)) {
- info = IEEE80211_SKB_CB(target_skb);
- range = (void *)info->rate_driver_data;
- target_addr = range->end_addr;
- }
- } else
- largest_hole = max(largest_hole, priv->rx_end - last_addr);
-
- if (!target_skb) {
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
- ieee80211_stop_queues(dev);
- return -ENOSPC;
- }
-
- info = IEEE80211_SKB_CB(skb);
- range = (void *)info->rate_driver_data;
- range->start_addr = target_addr;
- range->end_addr = target_addr + len;
- __skb_queue_after(&priv->tx_queue, target_skb, skb);
- spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-
- if (largest_hole < priv->headroom + sizeof(struct p54_hdr) +
- 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom)
- ieee80211_stop_queues(dev);
-
- data->req_id = cpu_to_le32(target_addr + priv->headroom);
- return 0;
-}
-
-static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, u16 hdr_flags,
- u16 payload_len, u16 type, gfp_t memflags)
-{
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr;
- struct sk_buff *skb;
- size_t frame_len = sizeof(*hdr) + payload_len;
-
- if (frame_len > P54_MAX_CTRL_FRAME_LEN)
- return NULL;
-
- skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
- if (!skb)
- return NULL;
- skb_reserve(skb, priv->tx_hdr_len);
-
- hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
- hdr->flags = cpu_to_le16(hdr_flags);
- hdr->len = cpu_to_le16(payload_len);
- hdr->type = cpu_to_le16(type);
- hdr->tries = hdr->rts_tries = 0;
-
- if (p54_assign_address(dev, skb, hdr, frame_len)) {
- kfree_skb(skb);
- return NULL;
- }
- return skb;
-}
-
-int p54_read_eeprom(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct p54_eeprom_lm86 *eeprom_hdr;
- struct sk_buff *skb;
- size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
- int ret = -ENOMEM;
- void *eeprom = NULL;
-
- maxblocksize = EEPROM_READBACK_LEN;
- if (priv->fw_var >= 0x509)
- maxblocksize -= 0xc;
- else
- maxblocksize -= 0x4;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*eeprom_hdr) +
- maxblocksize, P54_CONTROL_TYPE_EEPROM_READBACK,
- GFP_KERNEL);
- if (!skb)
- goto free;
- priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL);
- if (!priv->eeprom)
- goto free;
- eeprom = kzalloc(eeprom_size, GFP_KERNEL);
- if (!eeprom)
- goto free;
-
- eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
- sizeof(*eeprom_hdr) + maxblocksize);
-
- while (eeprom_size) {
- blocksize = min(eeprom_size, maxblocksize);
- if (priv->fw_var < 0x509) {
- eeprom_hdr->v1.offset = cpu_to_le16(offset);
- eeprom_hdr->v1.len = cpu_to_le16(blocksize);
- } else {
- eeprom_hdr->v2.offset = cpu_to_le32(offset);
- eeprom_hdr->v2.len = cpu_to_le16(blocksize);
- eeprom_hdr->v2.magic2 = 0xf;
- memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
- }
- priv->tx(dev, skb);
-
- if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) {
- printk(KERN_ERR "%s: device does not respond!\n",
- wiphy_name(dev->wiphy));
- ret = -EBUSY;
- goto free;
- }
-
- memcpy(eeprom + offset, priv->eeprom, blocksize);
- offset += blocksize;
- eeprom_size -= blocksize;
- }
-
- ret = p54_parse_eeprom(dev, eeprom, offset);
-free:
- kfree(priv->eeprom);
- priv->eeprom = NULL;
- p54_free_skb(dev, skb);
- kfree(eeprom);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(p54_read_eeprom);
-
-static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
- bool set)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_tim *tim;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
- P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
- tim->count = 1;
- tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid);
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_sta_unlock *sta;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
- P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
- memcpy(sta->addr, addr, ETH_ALEN);
- priv->tx(dev, skb);
- return 0;
-}
-
-static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
- enum sta_notify_cmd notify_cmd,
- struct ieee80211_sta *sta)
-{
- switch (notify_cmd) {
- case STA_NOTIFY_ADD:
- case STA_NOTIFY_REMOVE:
- /*
- * Notify the firmware that we don't want or we don't
- * need to buffer frames for this station anymore.
- */
-
- p54_sta_unlock(dev, sta->addr);
- break;
- case STA_NOTIFY_AWAKE:
- /* update the firmware's filter table */
- p54_sta_unlock(dev, sta->addr);
- break;
- default:
- break;
- }
-}
-
-static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_hdr *hdr;
- struct p54_txcancel *cancel;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
- P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- hdr = (void *)entry->data;
- cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
- cancel->req_id = hdr->req_id;
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb,
- struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len,
- u16 *flags, u16 *aid)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct p54_common *priv = dev->priv;
- int ret = 1;
-
- switch (priv->mode) {
- case NL80211_IFTYPE_MONITOR:
- /*
- * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
- * every frame in promiscuous/monitor mode.
- * see STSW45x0C LMAC API - page 12.
- */
- *aid = 0;
- *flags = P54_HDR_FLAG_DATA_OUT_PROMISC;
- *queue += P54_QUEUE_DATA;
- break;
- case NL80211_IFTYPE_STATION:
- *aid = 1;
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- *queue = P54_QUEUE_MGMT;
- ret = 0;
- } else
- *queue += P54_QUEUE_DATA;
- break;
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
- *aid = 0;
- *queue = P54_QUEUE_CAB;
- return 0;
- }
-
- if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
- if (ieee80211_is_probe_resp(hdr->frame_control)) {
- *aid = 0;
- *queue = P54_QUEUE_MGMT;
- *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
- P54_HDR_FLAG_DATA_OUT_NOCANCEL;
- return 0;
- } else if (ieee80211_is_beacon(hdr->frame_control)) {
- *aid = 0;
-
- if (info->flags & IEEE80211_TX_CTL_INJECTED) {
- /*
- * Injecting beacons on top of a AP is
- * not a good idea... nevertheless,
- * it should be doable.
- */
-
- *queue += P54_QUEUE_DATA;
- return 1;
- }
-
- *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
- *queue = P54_QUEUE_BEACON;
- *extra_len = IEEE80211_MAX_TIM_LEN;
- return 0;
- } else {
- *queue = P54_QUEUE_MGMT;
- ret = 0;
- }
- } else
- *queue += P54_QUEUE_DATA;
-
- if (info->control.sta)
- *aid = info->control.sta->aid;
-
- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
- *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
- break;
- }
- return ret;
-}
-
-static u8 p54_convert_algo(enum ieee80211_key_alg alg)
-{
- switch (alg) {
- case ALG_WEP:
- return P54_CRYPTO_WEP;
- case ALG_TKIP:
- return P54_CRYPTO_TKIPMICHAEL;
- case ALG_CCMP:
- return P54_CRYPTO_AESCCMP;
- default:
- return 0;
- }
-}
-
-static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_tx_queue_stats *current_queue;
- struct p54_common *priv = dev->priv;
- struct p54_hdr *hdr;
- struct p54_tx_data *txhdr;
- size_t padding, len, tim_len = 0;
- int i, j, ridx, ret;
- u16 hdr_flags = 0, aid = 0;
- u8 rate, queue, crypt_offset = 0;
- u8 cts_rate = 0x20;
- u8 rc_flags;
- u8 calculated_tries[4];
- u8 nrates = 0, nremaining = 8;
-
- queue = skb_get_queue_mapping(skb);
-
- ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid);
- current_queue = &priv->tx_stats[queue];
- if (unlikely((current_queue->len > current_queue->limit) && ret))
- return NETDEV_TX_BUSY;
- current_queue->len++;
- current_queue->count++;
- if ((current_queue->len == current_queue->limit) && ret)
- ieee80211_stop_queue(dev, skb_get_queue_mapping(skb));
-
- padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
- len = skb->len;
-
- if (info->control.hw_key) {
- crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
- if (info->control.hw_key->alg == ALG_TKIP) {
- u8 *iv = (u8 *)(skb->data + crypt_offset);
- /*
- * The firmware excepts that the IV has to have
- * this special format
- */
- iv[1] = iv[0];
- iv[0] = iv[2];
- iv[2] = 0;
- }
- }
-
- txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
- hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
-
- if (padding)
- hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
- hdr->type = cpu_to_le16(aid);
- hdr->rts_tries = info->control.rates[0].count;
-
- /*
- * we register the rates in perfect order, and
- * RTS/CTS won't happen on 5 GHz
- */
- cts_rate = info->control.rts_cts_rate_idx;
-
- memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
-
- /* see how many rates got used */
- for (i = 0; i < 4; i++) {
- if (info->control.rates[i].idx < 0)
- break;
- nrates++;
- }
-
- /* limit tries to 8/nrates per rate */
- for (i = 0; i < nrates; i++) {
- /*
- * The magic expression here is equivalent to 8/nrates for
- * all values that matter, but avoids division and jumps.
- * Note that nrates can only take the values 1 through 4.
- */
- calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
- info->control.rates[i].count);
- nremaining -= calculated_tries[i];
- }
-
- /* if there are tries left, distribute from back to front */
- for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
- int tmp = info->control.rates[i].count - calculated_tries[i];
-
- if (tmp <= 0)
- continue;
- /* RC requested more tries at this rate */
-
- tmp = min_t(int, tmp, nremaining);
- calculated_tries[i] += tmp;
- nremaining -= tmp;
- }
-
- ridx = 0;
- for (i = 0; i < nrates && ridx < 8; i++) {
- /* we register the rates in perfect order */
- rate = info->control.rates[i].idx;
- if (info->band == IEEE80211_BAND_5GHZ)
- rate += 4;
-
- /* store the count we actually calculated for TX status */
- info->control.rates[i].count = calculated_tries[i];
-
- rc_flags = info->control.rates[i].flags;
- if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
- rate |= 0x10;
- cts_rate |= 0x10;
- }
- if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
- rate |= 0x40;
- else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
- rate |= 0x20;
- for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
- txhdr->rateset[ridx] = rate;
- ridx++;
- }
- }
-
- if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
- hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
-
- /* TODO: enable bursting */
- hdr->flags = cpu_to_le16(hdr_flags);
- hdr->tries = ridx;
- txhdr->rts_rate_idx = 0;
- if (info->control.hw_key) {
- txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
- txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
- memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
- if (info->control.hw_key->alg == ALG_TKIP) {
- if (unlikely(skb_tailroom(skb) < 12))
- goto err;
- /* reserve space for the MIC key */
- len += 8;
- memcpy(skb_put(skb, 8), &(info->control.hw_key->key
- [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
- }
- /* reserve some space for ICV */
- len += info->control.hw_key->icv_len;
- memset(skb_put(skb, info->control.hw_key->icv_len), 0,
- info->control.hw_key->icv_len);
- } else {
- txhdr->key_type = 0;
- txhdr->key_len = 0;
- }
- txhdr->crypt_offset = crypt_offset;
- txhdr->hw_queue = queue;
- txhdr->backlog = current_queue->len;
- memset(txhdr->durations, 0, sizeof(txhdr->durations));
- txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
- 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- txhdr->longbow.cts_rate = cts_rate;
- txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
- } else {
- txhdr->normal.output_power = priv->output_power;
- txhdr->normal.cts_rate = cts_rate;
- }
- if (padding)
- txhdr->align[0] = padding;
-
- hdr->len = cpu_to_le16(len);
- /* modifies skb->cb and with it info, so must be last! */
- if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len)))
- goto err;
- priv->tx(dev, skb);
-
- queue_delayed_work(dev->workqueue, &priv->work,
- msecs_to_jiffies(P54_TX_FRAME_LIFETIME));
-
- return NETDEV_TX_OK;
-
- err:
- skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding);
- current_queue->len--;
- current_queue->count--;
- return NETDEV_TX_BUSY;
-}
-
-static int p54_setup_mac(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_setup_mac *setup;
- u16 mode;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
- P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
- if (dev->conf.radio_enabled) {
- switch (priv->mode) {
- case NL80211_IFTYPE_STATION:
- mode = P54_FILTER_TYPE_STATION;
- break;
- case NL80211_IFTYPE_AP:
- mode = P54_FILTER_TYPE_AP;
- break;
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- mode = P54_FILTER_TYPE_IBSS;
- break;
- case NL80211_IFTYPE_MONITOR:
- mode = P54_FILTER_TYPE_PROMISCUOUS;
- break;
- default:
- mode = P54_FILTER_TYPE_HIBERNATE;
- break;
- }
-
- /*
- * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
- * STSW45X0C LMAC API - page 12
- */
- if (((priv->filter_flags & FIF_PROMISC_IN_BSS) ||
- (priv->filter_flags & FIF_OTHER_BSS)) &&
- (mode != P54_FILTER_TYPE_PROMISCUOUS))
- mode |= P54_FILTER_TYPE_TRANSPARENT;
- } else
- mode = P54_FILTER_TYPE_HIBERNATE;
-
- setup->mac_mode = cpu_to_le16(mode);
- memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
- memcpy(setup->bssid, priv->bssid, ETH_ALEN);
- setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
- setup->rx_align = 0;
- if (priv->fw_var < 0x500) {
- setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- memset(setup->v1.rts_rates, 0, 8);
- setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
- setup->v1.rxhw = cpu_to_le16(priv->rxhw);
- setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
- setup->v1.unalloc0 = cpu_to_le16(0);
- } else {
- setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
- setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
- setup->v2.rxhw = cpu_to_le16(priv->rxhw);
- setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
- setup->v2.truncate = cpu_to_le16(48896);
- setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- setup->v2.sbss_offset = 0;
- setup->v2.mcast_window = 0;
- setup->v2.rx_rssi_threshold = 0;
- setup->v2.rx_ed_threshold = 0;
- setup->v2.ref_clock = cpu_to_le32(644245094);
- setup->v2.lpf_bandwidth = cpu_to_le16(65535);
- setup->v2.osc_start_delay = cpu_to_le16(65535);
- }
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_hdr *hdr;
- struct p54_scan_head *head;
- struct p54_iq_autocal_entry *iq_autocal;
- union p54_scan_body_union *body;
- struct p54_scan_tail_rate *rate;
- struct pda_rssi_cal_entry *rssi;
- unsigned int i;
- void *entry;
- int band = dev->conf.channel->band;
- __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
- 2 + sizeof(*iq_autocal) + sizeof(*body) +
- sizeof(*rate) + 2 * sizeof(*rssi),
- P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
- memset(head->scan_params, 0, sizeof(head->scan_params));
- head->mode = cpu_to_le16(mode);
- head->dwell = cpu_to_le16(dwell);
- head->freq = freq;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
- *pa_power_points = cpu_to_le16(0x0c);
- }
-
- iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
- for (i = 0; i < priv->iq_autocal_len; i++) {
- if (priv->iq_autocal[i].freq != freq)
- continue;
-
- memcpy(iq_autocal, &priv->iq_autocal[i].params,
- sizeof(struct p54_iq_autocal_entry));
- break;
- }
- if (i == priv->iq_autocal_len)
- goto err;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
- body = (void *) skb_put(skb, sizeof(body->longbow));
- else
- body = (void *) skb_put(skb, sizeof(body->normal));
-
- for (i = 0; i < priv->output_limit->entries; i++) {
- __le16 *entry_freq = (void *) (priv->output_limit->data +
- priv->output_limit->entry_size * i);
-
- if (*entry_freq != freq)
- continue;
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- memcpy(&body->longbow.power_limits,
- (void *) entry_freq + sizeof(__le16),
- priv->output_limit->entry_size);
- } else {
- struct pda_channel_output_limit *limits =
- (void *) entry_freq;
-
- body->normal.val_barker = 0x38;
- body->normal.val_bpsk = body->normal.dup_bpsk =
- limits->val_bpsk;
- body->normal.val_qpsk = body->normal.dup_qpsk =
- limits->val_qpsk;
- body->normal.val_16qam = body->normal.dup_16qam =
- limits->val_16qam;
- body->normal.val_64qam = body->normal.dup_64qam =
- limits->val_64qam;
- }
- break;
- }
- if (i == priv->output_limit->entries)
- goto err;
-
- entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
- for (i = 0; i < priv->curve_data->entries; i++) {
- if (*((__le16 *)entry) != freq) {
- entry += priv->curve_data->entry_size;
- continue;
- }
-
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- memcpy(&body->longbow.curve_data,
- (void *) entry + sizeof(__le16),
- priv->curve_data->entry_size);
- } else {
- struct p54_scan_body *chan = &body->normal;
- struct pda_pa_curve_data *curve_data =
- (void *) priv->curve_data->data;
-
- entry += sizeof(__le16);
- chan->pa_points_per_curve = 8;
- memset(chan->curve_data, 0, sizeof(*chan->curve_data));
- memcpy(chan->curve_data, entry,
- sizeof(struct p54_pa_curve_data_sample) *
- min((u8)8, curve_data->points_per_channel));
- }
- break;
- }
- if (i == priv->curve_data->entries)
- goto err;
-
- if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
- rate = (void *) skb_put(skb, sizeof(*rate));
- rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- for (i = 0; i < sizeof(rate->rts_rates); i++)
- rate->rts_rates[i] = i;
- }
-
- rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
- rssi->mul = cpu_to_le16(priv->rssical_db[band].mul);
- rssi->add = cpu_to_le16(priv->rssical_db[band].add);
- if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
- /* Longbow frontend needs ever more */
- rssi = (void *) skb_put(skb, sizeof(*rssi));
- rssi->mul = cpu_to_le16(priv->rssical_db[band].longbow_unkn);
- rssi->add = cpu_to_le16(priv->rssical_db[band].longbow_unk2);
- }
-
- if (priv->fw_var >= 0x509) {
- rate = (void *) skb_put(skb, sizeof(*rate));
- rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
- for (i = 0; i < sizeof(rate->rts_rates); i++)
- rate->rts_rates[i] = i;
- }
-
- hdr = (struct p54_hdr *) skb->data;
- hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
-
- priv->tx(dev, skb);
- return 0;
-
- err:
- printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
- p54_free_skb(dev, skb);
- return -EINVAL;
-}
-
-static int p54_set_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_led *led;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
- P54_CONTROL_TYPE_LED, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- led = (struct p54_led *) skb_put(skb, sizeof(*led));
- led->flags = cpu_to_le16(0x0003);
- led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
- led->delay[0] = cpu_to_le16(1);
- led->delay[1] = cpu_to_le16(0);
- priv->tx(dev, skb);
- return 0;
-}
-
-#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \
-do { \
- queue.aifs = cpu_to_le16(ai_fs); \
- queue.cwmin = cpu_to_le16(cw_min); \
- queue.cwmax = cpu_to_le16(cw_max); \
- queue.txop = cpu_to_le16(_txop); \
-} while(0)
-
-static int p54_set_edcf(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_edcf *edcf;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
- P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
- if (priv->use_short_slot) {
- edcf->slottime = 9;
- edcf->sifs = 0x10;
- edcf->eofpad = 0x00;
- } else {
- edcf->slottime = 20;
- edcf->sifs = 0x0a;
- edcf->eofpad = 0x06;
- }
- /* (see prism54/isl_oid.h for further details) */
- edcf->frameburst = cpu_to_le16(0);
- edcf->round_trip_delay = cpu_to_le16(0);
- edcf->flags = 0;
- memset(edcf->mapping, 0, sizeof(edcf->mapping));
- memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
- priv->tx(dev, skb);
- return 0;
-}
-
-static int p54_set_ps(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_psm *psm;
- u16 mode;
- int i;
-
- if (dev->conf.flags & IEEE80211_CONF_PS)
- mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
- P54_PSM_CHECKSUM | P54_PSM_MCBC;
- else
- mode = P54_PSM_CAM;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
- P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
- if (!skb)
- return -ENOMEM;
-
- psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
- psm->mode = cpu_to_le16(mode);
- psm->aid = cpu_to_le16(priv->aid);
- for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
- psm->intervals[i].interval =
- cpu_to_le16(dev->conf.listen_interval);
- psm->intervals[i].periods = cpu_to_le16(1);
- }
-
- psm->beacon_rssi_skip_max = 200;
- psm->rssi_delta_threshold = 0;
- psm->nr = 10;
- psm->exclude[0] = 0;
-
- priv->tx(dev, skb);
-
- return 0;
-}
-
-static int p54_beacon_tim(struct sk_buff *skb)
-{
- /*
- * the good excuse for this mess is ... the firmware.
- * The dummy TIM MUST be at the end of the beacon frame,
- * because it'll be overwritten!
- */
-
- struct ieee80211_mgmt *mgmt = (void *)skb->data;
- u8 *pos, *end;
-
- if (skb->len <= sizeof(mgmt))
- return -EINVAL;
-
- pos = (u8 *)mgmt->u.beacon.variable;
- end = skb->data + skb->len;
- while (pos < end) {
- if (pos + 2 + pos[1] > end)
- return -EINVAL;
-
- if (pos[0] == WLAN_EID_TIM) {
- u8 dtim_len = pos[1];
- u8 dtim_period = pos[3];
- u8 *next = pos + 2 + dtim_len;
-
- if (dtim_len < 3)
- return -EINVAL;
-
- memmove(pos, next, end - next);
-
- if (dtim_len > 3)
- skb_trim(skb, skb->len - (dtim_len - 3));
-
- pos = end - (dtim_len + 2);
-
- /* add the dummy at the end */
- pos[0] = WLAN_EID_TIM;
- pos[1] = 3;
- pos[2] = 0;
- pos[3] = dtim_period;
- pos[4] = 0;
- return 0;
- }
- pos += 2 + pos[1];
- }
- return 0;
-}
-
-static int p54_beacon_update(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *beacon;
- int ret;
-
- if (priv->cached_beacon) {
- p54_tx_cancel(dev, priv->cached_beacon);
- /* wait for the last beacon the be freed */
- msleep(10);
- }
-
- beacon = ieee80211_beacon_get(dev, vif);
- if (!beacon)
- return -ENOMEM;
- ret = p54_beacon_tim(beacon);
- if (ret)
- return ret;
- ret = p54_tx(dev, beacon);
- if (ret)
- return ret;
- priv->cached_beacon = beacon;
- priv->tsf_high32 = 0;
- priv->tsf_low32 = 0;
-
- return 0;
-}
-
-static int p54_start(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int err;
-
- mutex_lock(&priv->conf_mutex);
- err = priv->open(dev);
- if (err)
- goto out;
- P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
- P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
- P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
- P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
- err = p54_set_edcf(dev);
- if (err)
- goto out;
-
- memset(priv->bssid, ~0, ETH_ALEN);
- priv->mode = NL80211_IFTYPE_MONITOR;
- err = p54_setup_mac(dev);
- if (err) {
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- goto out;
- }
-
- queue_delayed_work(dev->workqueue, &priv->work, 0);
-
- priv->softled_state = 0;
- err = p54_set_leds(dev);
-
-out:
- mutex_unlock(&priv->conf_mutex);
- return err;
-}
-
-static void p54_stop(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
-
- mutex_lock(&priv->conf_mutex);
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->softled_state = 0;
- p54_set_leds(dev);
-
-#ifdef CONFIG_P54_LEDS
- cancel_delayed_work_sync(&priv->led_work);
-#endif /* CONFIG_P54_LEDS */
- cancel_delayed_work_sync(&priv->work);
- if (priv->cached_beacon)
- p54_tx_cancel(dev, priv->cached_beacon);
-
- priv->stop(dev);
- while ((skb = skb_dequeue(&priv->tx_queue)))
- kfree_skb(skb);
- priv->cached_beacon = NULL;
- priv->tsf_high32 = priv->tsf_low32 = 0;
- mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct p54_common *priv = dev->priv;
-
- mutex_lock(&priv->conf_mutex);
- if (priv->mode != NL80211_IFTYPE_MONITOR) {
- mutex_unlock(&priv->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- priv->vif = conf->vif;
-
- switch (conf->type) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_MESH_POINT:
- priv->mode = conf->type;
- break;
- default:
- mutex_unlock(&priv->conf_mutex);
- return -EOPNOTSUPP;
- }
-
- memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
- p54_setup_mac(dev);
- mutex_unlock(&priv->conf_mutex);
- return 0;
-}
-
-static void p54_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct p54_common *priv = dev->priv;
-
- mutex_lock(&priv->conf_mutex);
- priv->vif = NULL;
- if (priv->cached_beacon)
- p54_tx_cancel(dev, priv->cached_beacon);
- priv->mode = NL80211_IFTYPE_MONITOR;
- memset(priv->mac_addr, 0, ETH_ALEN);
- memset(priv->bssid, 0, ETH_ALEN);
- p54_setup_mac(dev);
- mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_config(struct ieee80211_hw *dev, u32 changed)
-{
- int ret = 0;
- struct p54_common *priv = dev->priv;
- struct ieee80211_conf *conf = &dev->conf;
-
- mutex_lock(&priv->conf_mutex);
- if (changed & IEEE80211_CONF_CHANGE_POWER)
- priv->output_power = conf->power_level << 2;
- if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- }
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- ret = p54_scan(dev, P54_SCAN_EXIT, 0);
- if (ret)
- goto out;
- }
- if (changed & IEEE80211_CONF_CHANGE_PS) {
- ret = p54_set_ps(dev);
- if (ret)
- goto out;
- }
-
-out:
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-static void p54_configure_filter(struct ieee80211_hw *dev,
- unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count, struct dev_mc_list *mclist)
-{
- struct p54_common *priv = dev->priv;
-
- *total_flags &= FIF_PROMISC_IN_BSS |
- FIF_OTHER_BSS;
-
- priv->filter_flags = *total_flags;
-
- if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
- p54_setup_mac(dev);
-}
-
-static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct p54_common *priv = dev->priv;
- int ret;
-
- mutex_lock(&priv->conf_mutex);
- if ((params) && !(queue > 4)) {
- P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
- params->cw_min, params->cw_max, params->txop);
- ret = p54_set_edcf(dev);
- } else
- ret = -EINVAL;
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-static int p54_init_xbow_synth(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_xbow_synth *xbow;
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
- P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
- if (!skb)
- return -ENOMEM;
-
- xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
- xbow->magic1 = cpu_to_le16(0x1);
- xbow->magic2 = cpu_to_le16(0x2);
- xbow->freq = cpu_to_le16(5390);
- memset(xbow->padding, 0, sizeof(xbow->padding));
- priv->tx(dev, skb);
- return 0;
-}
-
-static void p54_work(struct work_struct *work)
-{
- struct p54_common *priv = container_of(work, struct p54_common,
- work.work);
- struct ieee80211_hw *dev = priv->hw;
- struct sk_buff *skb;
-
- if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
- return ;
-
- /*
- * TODO: walk through tx_queue and do the following tasks
- * 1. initiate bursts.
- * 2. cancel stuck frames / reset the device if necessary.
- */
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL,
- sizeof(struct p54_statistics),
- P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
- if (!skb)
- return ;
-
- priv->tx(dev, skb);
-}
-
-static int p54_get_stats(struct ieee80211_hw *dev,
- struct ieee80211_low_level_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->stats, sizeof(*stats));
- return 0;
-}
-
-static int p54_get_tx_stats(struct ieee80211_hw *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct p54_common *priv = dev->priv;
-
- memcpy(stats, &priv->tx_stats[P54_QUEUE_DATA],
- sizeof(stats[0]) * dev->queues);
- return 0;
-}
-
-static void p54_bss_info_changed(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed)
-{
- struct p54_common *priv = dev->priv;
- int ret;
-
- mutex_lock(&priv->conf_mutex);
- if (changed & BSS_CHANGED_BSSID) {
- memcpy(priv->bssid, info->bssid, ETH_ALEN);
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- }
-
- if (changed & BSS_CHANGED_BEACON) {
- ret = p54_scan(dev, P54_SCAN_EXIT, 0);
- if (ret)
- goto out;
- ret = p54_setup_mac(dev);
- if (ret)
- goto out;
- ret = p54_beacon_update(dev, vif);
- if (ret)
- goto out;
- }
- /* XXX: this mimics having two callbacks... clean up */
- out:
- mutex_unlock(&priv->conf_mutex);
-
- if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
- priv->use_short_slot = info->use_short_slot;
- p54_set_edcf(dev);
- }
- if (changed & BSS_CHANGED_BASIC_RATES) {
- if (dev->conf.channel->band == IEEE80211_BAND_5GHZ)
- priv->basic_rate_mask = (info->basic_rates << 4);
- else
- priv->basic_rate_mask = info->basic_rates;
- p54_setup_mac(dev);
- if (priv->fw_var >= 0x500)
- p54_scan(dev, P54_SCAN_EXIT, 0);
- }
- if (changed & BSS_CHANGED_ASSOC) {
- if (info->assoc) {
- priv->aid = info->aid;
- priv->wakeup_timer = info->beacon_int *
- info->dtim_period * 5;
- p54_setup_mac(dev);
- }
- }
-}
-
-static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct p54_common *priv = dev->priv;
- struct sk_buff *skb;
- struct p54_keycache *rxkey;
- int slot, ret = 0;
- u8 algo = 0;
-
- if (modparam_nohwcrypt)
- return -EOPNOTSUPP;
-
- mutex_lock(&priv->conf_mutex);
- if (cmd == SET_KEY) {
- switch (key->alg) {
- case ALG_TKIP:
- if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
- BR_DESC_PRIV_CAP_TKIP))) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_TKIPMICHAEL;
- break;
- case ALG_WEP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_WEP;
- break;
- case ALG_CCMP:
- if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- algo = P54_CRYPTO_AESCCMP;
- break;
- default:
- ret = -EOPNOTSUPP;
- goto out_unlock;
- }
- slot = bitmap_find_free_region(priv->used_rxkeys,
- priv->rx_keycache_size, 0);
-
- if (slot < 0) {
- /*
- * The device supports the choosen algorithm, but the
- * firmware does not provide enough key slots to store
- * all of them.
- * But encryption offload for outgoing frames is always
- * possible, so we just pretend that the upload was
- * successful and do the decryption in software.
- */
-
- /* mark the key as invalid. */
- key->hw_key_idx = 0xff;
- goto out_unlock;
- }
- } else {
- slot = key->hw_key_idx;
-
- if (slot == 0xff) {
- /* This key was not uploaded into the rx key cache. */
-
- goto out_unlock;
- }
-
- bitmap_release_region(priv->used_rxkeys, slot, 0);
- algo = 0;
- }
-
- skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
- P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
- if (!skb) {
- bitmap_release_region(priv->used_rxkeys, slot, 0);
- ret = -ENOSPC;
- goto out_unlock;
- }
-
- rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
- rxkey->entry = slot;
- rxkey->key_id = key->keyidx;
- rxkey->key_type = algo;
- if (sta)
- memcpy(rxkey->mac, sta->addr, ETH_ALEN);
- else
- memset(rxkey->mac, ~0, ETH_ALEN);
- if (key->alg != ALG_TKIP) {
- rxkey->key_len = min((u8)16, key->keylen);
- memcpy(rxkey->key, key->key, rxkey->key_len);
- } else {
- rxkey->key_len = 24;
- memcpy(rxkey->key, key->key, 16);
- memcpy(&(rxkey->key[16]), &(key->key
- [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
- }
-
- priv->tx(dev, skb);
- key->hw_key_idx = slot;
-
-out_unlock:
- mutex_unlock(&priv->conf_mutex);
- return ret;
-}
-
-#ifdef CONFIG_P54_LEDS
-static void p54_update_leds(struct work_struct *work)
-{
- struct p54_common *priv = container_of(work, struct p54_common,
- led_work.work);
- int err, i, tmp, blink_delay = 400;
- bool rerun = false;
-
- /* Don't toggle the LED, when the device is down. */
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
- if (priv->leds[i].toggled) {
- priv->softled_state |= BIT(i);
-
- tmp = 70 + 200 / (priv->leds[i].toggled);
- if (tmp < blink_delay)
- blink_delay = tmp;
-
- if (priv->leds[i].led_dev.brightness == LED_OFF)
- rerun = true;
-
- priv->leds[i].toggled =
- !!priv->leds[i].led_dev.brightness;
- } else
- priv->softled_state &= ~BIT(i);
-
- err = p54_set_leds(priv->hw);
- if (err && net_ratelimit())
- printk(KERN_ERR "%s: failed to update LEDs.\n",
- wiphy_name(priv->hw->wiphy));
-
- if (rerun)
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- msecs_to_jiffies(blink_delay));
-}
-
-static void p54_led_brightness_set(struct led_classdev *led_dev,
- enum led_brightness brightness)
-{
- struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
- led_dev);
- struct ieee80211_hw *dev = led->hw_dev;
- struct p54_common *priv = dev->priv;
-
- if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
- return ;
-
- if (brightness) {
- led->toggled++;
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- HZ/10);
- }
-}
-
-static int p54_register_led(struct ieee80211_hw *dev,
- unsigned int led_index,
- char *name, char *trigger)
-{
- struct p54_common *priv = dev->priv;
- struct p54_led_dev *led = &priv->leds[led_index];
- int err;
-
- if (led->registered)
- return -EEXIST;
-
- snprintf(led->name, sizeof(led->name), "p54-%s::%s",
- wiphy_name(dev->wiphy), name);
- led->hw_dev = dev;
- led->index = led_index;
- led->led_dev.name = led->name;
- led->led_dev.default_trigger = trigger;
- led->led_dev.brightness_set = p54_led_brightness_set;
-
- err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev);
- if (err)
- printk(KERN_ERR "%s: Failed to register %s LED.\n",
- wiphy_name(dev->wiphy), name);
- else
- led->registered = 1;
-
- return err;
-}
-
-static int p54_init_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int err;
-
- /*
- * TODO:
- * Figure out if the EEPROM contains some hints about the number
- * of available/programmable LEDs of the device.
- */
-
- INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
-
- err = p54_register_led(dev, 0, "assoc",
- ieee80211_get_assoc_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 1, "tx",
- ieee80211_get_tx_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 2, "rx",
- ieee80211_get_rx_led_name(dev));
- if (err)
- return err;
-
- err = p54_register_led(dev, 3, "radio",
- ieee80211_get_radio_led_name(dev));
- if (err)
- return err;
-
- err = p54_set_leds(dev);
- return err;
-}
-
-static void p54_unregister_leds(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
- if (priv->leds[i].registered)
- led_classdev_unregister(&priv->leds[i].led_dev);
-}
-#endif /* CONFIG_P54_LEDS */
-
-static const struct ieee80211_ops p54_ops = {
- .tx = p54_tx,
- .start = p54_start,
- .stop = p54_stop,
- .add_interface = p54_add_interface,
- .remove_interface = p54_remove_interface,
- .set_tim = p54_set_tim,
- .sta_notify = p54_sta_notify,
- .set_key = p54_set_key,
- .config = p54_config,
- .bss_info_changed = p54_bss_info_changed,
- .configure_filter = p54_configure_filter,
- .conf_tx = p54_conf_tx,
- .get_stats = p54_get_stats,
- .get_tx_stats = p54_get_tx_stats
-};
-
-struct ieee80211_hw *p54_init_common(size_t priv_data_len)
-{
- struct ieee80211_hw *dev;
- struct p54_common *priv;
-
- dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
- if (!dev)
- return NULL;
-
- priv = dev->priv;
- priv->hw = dev;
- priv->mode = NL80211_IFTYPE_UNSPECIFIED;
- priv->basic_rate_mask = 0x15f;
- skb_queue_head_init(&priv->tx_queue);
- dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_NOISE_DBM;
-
- dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC) |
- BIT(NL80211_IFTYPE_AP) |
- BIT(NL80211_IFTYPE_MESH_POINT);
-
- dev->channel_change_time = 1000; /* TODO: find actual value */
- priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
- priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
- priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
- priv->tx_stats[P54_QUEUE_CAB].limit = 3;
- priv->tx_stats[P54_QUEUE_DATA].limit = 5;
- dev->queues = 1;
- priv->noise = -94;
- /*
- * We support at most 8 tries no matter which rate they're at,
- * we cannot support max_rates * max_rate_tries as we set it
- * here, but setting it correctly to 4/2 or so would limit us
- * artificially if the RC algorithm wants just two rates, so
- * let's say 4/7, we'll redistribute it at TX time, see the
- * comments there.
- */
- dev->max_rates = 4;
- dev->max_rate_tries = 7;
- dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
- sizeof(struct p54_tx_data);
-
- mutex_init(&priv->conf_mutex);
- init_completion(&priv->eeprom_comp);
- INIT_DELAYED_WORK(&priv->work, p54_work);
-
- return dev;
-}
-EXPORT_SYMBOL_GPL(p54_init_common);
-
-int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
-{
- int err;
-
- err = ieee80211_register_hw(dev);
- if (err) {
- dev_err(pdev, "Cannot register device (%d).\n", err);
- return err;
- }
-
-#ifdef CONFIG_P54_LEDS
- err = p54_init_leds(dev);
- if (err)
- return err;
-#endif /* CONFIG_P54_LEDS */
-
- dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
- return 0;
-}
-EXPORT_SYMBOL_GPL(p54_register_common);
-
-void p54_free_common(struct ieee80211_hw *dev)
-{
- struct p54_common *priv = dev->priv;
- kfree(priv->iq_autocal);
- kfree(priv->output_limit);
- kfree(priv->curve_data);
- kfree(priv->used_rxkeys);
-
-#ifdef CONFIG_P54_LEDS
- p54_unregister_leds(dev);
-#endif /* CONFIG_P54_LEDS */
-}
-EXPORT_SYMBOL_GPL(p54_free_common);
diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h
deleted file mode 100644
index 75ead7a150f..00000000000
--- a/drivers/net/wireless/p54/p54common.h
+++ /dev/null
@@ -1,644 +0,0 @@
-#ifndef P54COMMON_H
-#define P54COMMON_H
-
-/*
- * Common code specific definitions for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
- * Copyright (C) 2007 Conexant Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-struct bootrec {
- __le32 code;
- __le32 len;
- u32 data[10];
-} __attribute__((packed));
-
-#define PDR_SYNTH_FRONTEND_MASK 0x0007
-#define PDR_SYNTH_FRONTEND_DUETTE3 0x0001
-#define PDR_SYNTH_FRONTEND_DUETTE2 0x0002
-#define PDR_SYNTH_FRONTEND_FRISBEE 0x0003
-#define PDR_SYNTH_FRONTEND_XBOW 0x0004
-#define PDR_SYNTH_FRONTEND_LONGBOW 0x0005
-#define PDR_SYNTH_IQ_CAL_MASK 0x0018
-#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000
-#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008
-#define PDR_SYNTH_IQ_CAL_ZIF 0x0010
-#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020
-#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0020
-#define PDR_SYNTH_24_GHZ_MASK 0x0040
-#define PDR_SYNTH_24_GHZ_DISABLED 0x0040
-#define PDR_SYNTH_5_GHZ_MASK 0x0080
-#define PDR_SYNTH_5_GHZ_DISABLED 0x0080
-#define PDR_SYNTH_RX_DIV_MASK 0x0100
-#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100
-#define PDR_SYNTH_TX_DIV_MASK 0x0200
-#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200
-
-struct bootrec_exp_if {
- __le16 role;
- __le16 if_id;
- __le16 variant;
- __le16 btm_compat;
- __le16 top_compat;
-} __attribute__((packed));
-
-#define BR_DESC_PRIV_CAP_WEP BIT(0)
-#define BR_DESC_PRIV_CAP_TKIP BIT(1)
-#define BR_DESC_PRIV_CAP_MICHAEL BIT(2)
-#define BR_DESC_PRIV_CAP_CCX_CP BIT(3)
-#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4)
-#define BR_DESC_PRIV_CAP_AESCCMP BIT(5)
-
-struct bootrec_desc {
- __le16 modes;
- __le16 flags;
- __le32 rx_start;
- __le32 rx_end;
- u8 headroom;
- u8 tailroom;
- u8 tx_queues;
- u8 tx_depth;
- u8 privacy_caps;
- u8 rx_keycache_size;
- u8 time_size;
- u8 padding;
- u8 rates[16];
- u8 padding2[4];
- __le16 rx_mtu;
-} __attribute__((packed));
-
-#define BR_CODE_MIN 0x80000000
-#define BR_CODE_COMPONENT_ID 0x80000001
-#define BR_CODE_COMPONENT_VERSION 0x80000002
-#define BR_CODE_DEPENDENT_IF 0x80000003
-#define BR_CODE_EXPOSED_IF 0x80000004
-#define BR_CODE_DESCR 0x80000101
-#define BR_CODE_MAX 0x8FFFFFFF
-#define BR_CODE_END_OF_BRA 0xFF0000FF
-#define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF
-
-#define P54_HDR_FLAG_DATA_ALIGN BIT(14)
-#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0)
-#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1)
-#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2)
-#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3)
-#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4)
-#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5)
-#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6)
-#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7)
-#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8)
-#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9)
-#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10)
-#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11)
-
-#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0)
-#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1)
-#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2)
-#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3)
-#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4)
-#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5)
-#define P54_HDR_FLAG_DATA_IN_DATA BIT(6)
-#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7)
-#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8)
-#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9)
-
-/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
-
-struct pda_entry {
- __le16 len; /* includes both code and data */
- __le16 code;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct eeprom_pda_wrap {
- __le32 magic;
- __le16 pad;
- __le16 len;
- __le32 arm_opcode;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct p54_iq_autocal_entry {
- __le16 iq_param[4];
-} __attribute__ ((packed));
-
-struct pda_iq_autocal_entry {
- __le16 freq;
- struct p54_iq_autocal_entry params;
-} __attribute__ ((packed));
-
-struct pda_channel_output_limit {
- __le16 freq;
- u8 val_bpsk;
- u8 val_qpsk;
- u8 val_16qam;
- u8 val_64qam;
- u8 rate_set_mask;
- u8 rate_set_size;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev0 {
- u8 rf_power;
- u8 pa_detector;
- u8 pcv;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data_sample_rev1 {
- u8 rf_power;
- u8 pa_detector;
- u8 data_barker;
- u8 data_bpsk;
- u8 data_qpsk;
- u8 data_16qam;
- u8 data_64qam;
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample {
- u8 rf_power;
- u8 pa_detector;
- u8 data_barker;
- u8 data_bpsk;
- u8 data_qpsk;
- u8 data_16qam;
- u8 data_64qam;
- u8 padding;
-} __attribute__ ((packed));
-
-struct pda_pa_curve_data {
- u8 cal_method_rev;
- u8 channels;
- u8 points_per_channel;
- u8 padding;
- u8 data[0];
-} __attribute__ ((packed));
-
-struct pda_rssi_cal_entry {
- __le16 mul;
- __le16 add;
-} __attribute__ ((packed));
-
-struct pda_country {
- u8 regdomain;
- u8 alpha2[2];
- u8 flags;
-} __attribute__ ((packed));
-
-/*
- * Warning: Longbow's structures are bogus.
- */
-struct p54_channel_output_limit_longbow {
- __le16 rf_power_points[12];
-} __attribute__ ((packed));
-
-struct p54_pa_curve_data_sample_longbow {
- __le16 rf_power;
- __le16 pa_detector;
- struct {
- __le16 data[4];
- } points[3] __attribute__ ((packed));
-} __attribute__ ((packed));
-
-struct pda_custom_wrapper {
- __le16 entries;
- __le16 entry_size;
- __le16 offset;
- __le16 len;
- u8 data[0];
-} __attribute__ ((packed));
-
-/*
- * this defines the PDR codes used to build PDAs as defined in document
- * number 553155. The current implementation mirrors version 1.1 of the
- * document and lists only PDRs supported by the ARM platform.
- */
-
-/* common and choice range (0x0000 - 0x0fff) */
-#define PDR_END 0x0000
-#define PDR_MANUFACTURING_PART_NUMBER 0x0001
-#define PDR_PDA_VERSION 0x0002
-#define PDR_NIC_SERIAL_NUMBER 0x0003
-
-#define PDR_MAC_ADDRESS 0x0101
-#define PDR_REGULATORY_DOMAIN_LIST 0x0103
-#define PDR_TEMPERATURE_TYPE 0x0107
-
-#define PDR_PRISM_PCI_IDENTIFIER 0x0402
-
-/* ARM range (0x1000 - 0x1fff) */
-#define PDR_COUNTRY_INFORMATION 0x1000
-#define PDR_INTERFACE_LIST 0x1001
-#define PDR_HARDWARE_PLATFORM_COMPONENT_ID 0x1002
-#define PDR_OEM_NAME 0x1003
-#define PDR_PRODUCT_NAME 0x1004
-#define PDR_UTF8_OEM_NAME 0x1005
-#define PDR_UTF8_PRODUCT_NAME 0x1006
-#define PDR_COUNTRY_LIST 0x1007
-#define PDR_DEFAULT_COUNTRY 0x1008
-
-#define PDR_ANTENNA_GAIN 0x1100
-
-#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA 0x1901
-#define PDR_RSSI_LINEAR_APPROXIMATION 0x1902
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS 0x1903
-#define PDR_PRISM_PA_CAL_CURVE_DATA 0x1904
-#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND 0x1905
-#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION 0x1906
-#define PDR_REGULATORY_POWER_LIMITS 0x1907
-#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
-#define PDR_RADIATED_TRANSMISSION_CORRECTION 0x1909
-#define PDR_PRISM_TX_IQ_CALIBRATION 0x190a
-
-/* reserved range (0x2000 - 0x7fff) */
-
-/* customer range (0x8000 - 0xffff) */
-#define PDR_BASEBAND_REGISTERS 0x8000
-#define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001
-
-/* used by our modificated eeprom image */
-#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM 0xDEAD
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM 0xBEEF
-#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM 0xB05D
-
-/* PDR definitions for default country & country list */
-#define PDR_COUNTRY_CERT_CODE 0x80
-#define PDR_COUNTRY_CERT_CODE_REAL 0x00
-#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80
-#define PDR_COUNTRY_CERT_BAND 0x40
-#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00
-#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40
-#define PDR_COUNTRY_CERT_IODOOR 0x30
-#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00
-#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
-#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30
-#define PDR_COUNTRY_CERT_INDEX 0x0F
-
-struct p54_eeprom_lm86 {
- union {
- struct {
- __le16 offset;
- __le16 len;
- u8 data[0];
- } v1;
- struct {
- __le32 offset;
- __le16 len;
- u8 magic2;
- u8 pad;
- u8 magic[4];
- u8 data[0];
- } v2;
- } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-enum p54_rx_decrypt_status {
- P54_DECRYPT_NONE = 0,
- P54_DECRYPT_OK,
- P54_DECRYPT_NOKEY,
- P54_DECRYPT_NOMICHAEL,
- P54_DECRYPT_NOCKIPMIC,
- P54_DECRYPT_FAIL_WEP,
- P54_DECRYPT_FAIL_TKIP,
- P54_DECRYPT_FAIL_MICHAEL,
- P54_DECRYPT_FAIL_CKIPKP,
- P54_DECRYPT_FAIL_CKIPMIC,
- P54_DECRYPT_FAIL_AESCCMP
-};
-
-struct p54_rx_data {
- __le16 flags;
- __le16 len;
- __le16 freq;
- u8 antenna;
- u8 rate;
- u8 rssi;
- u8 quality;
- u8 decrypt_status;
- u8 rssi_raw;
- __le32 tsf32;
- __le32 unalloc0;
- u8 align[0];
-} __attribute__ ((packed));
-
-enum p54_trap_type {
- P54_TRAP_SCAN = 0,
- P54_TRAP_TIMER,
- P54_TRAP_BEACON_TX,
- P54_TRAP_FAA_RADIO_ON,
- P54_TRAP_FAA_RADIO_OFF,
- P54_TRAP_RADAR,
- P54_TRAP_NO_BEACON,
- P54_TRAP_TBTT,
- P54_TRAP_SCO_ENTER,
- P54_TRAP_SCO_EXIT
-};
-
-struct p54_trap {
- __le16 event;
- __le16 frequency;
-} __attribute__ ((packed));
-
-enum p54_frame_sent_status {
- P54_TX_OK = 0,
- P54_TX_FAILED,
- P54_TX_PSM,
- P54_TX_PSM_CANCELLED = 4
-};
-
-struct p54_frame_sent {
- u8 status;
- u8 tries;
- u8 ack_rssi;
- u8 quality;
- __le16 seq;
- u8 antenna;
- u8 padding;
-} __attribute__ ((packed));
-
-enum p54_tx_data_crypt {
- P54_CRYPTO_NONE = 0,
- P54_CRYPTO_WEP,
- P54_CRYPTO_TKIP,
- P54_CRYPTO_TKIPMICHAEL,
- P54_CRYPTO_CCX_WEPMIC,
- P54_CRYPTO_CCX_KPMIC,
- P54_CRYPTO_CCX_KP,
- P54_CRYPTO_AESCCMP
-};
-
-enum p54_tx_data_queue {
- P54_QUEUE_BEACON = 0,
- P54_QUEUE_FWSCAN = 1,
- P54_QUEUE_MGMT = 2,
- P54_QUEUE_CAB = 3,
- P54_QUEUE_DATA = 4,
-
- P54_QUEUE_AC_NUM = 4,
- P54_QUEUE_AC_VO = 4,
- P54_QUEUE_AC_VI = 5,
- P54_QUEUE_AC_BE = 6,
- P54_QUEUE_AC_BK = 7,
-
- /* keep last */
- P54_QUEUE_NUM = 8,
-};
-
-struct p54_tx_data {
- u8 rateset[8];
- u8 rts_rate_idx;
- u8 crypt_offset;
- u8 key_type;
- u8 key_len;
- u8 key[16];
- u8 hw_queue;
- u8 backlog;
- __le16 durations[4];
- u8 tx_antenna;
- union {
- struct {
- u8 cts_rate;
- __le16 output_power;
- } __attribute__((packed)) longbow;
- struct {
- u8 output_power;
- u8 cts_rate;
- u8 unalloc;
- } __attribute__ ((packed)) normal;
- } __attribute__ ((packed));
- u8 unalloc2[2];
- u8 align[0];
-} __attribute__ ((packed));
-
-/* unit is ms */
-#define P54_TX_FRAME_LIFETIME 2000
-#define P54_TX_TIMEOUT 4000
-#define P54_STATISTICS_UPDATE 5000
-
-#define P54_FILTER_TYPE_NONE 0
-#define P54_FILTER_TYPE_STATION BIT(0)
-#define P54_FILTER_TYPE_IBSS BIT(1)
-#define P54_FILTER_TYPE_AP BIT(2)
-#define P54_FILTER_TYPE_TRANSPARENT BIT(3)
-#define P54_FILTER_TYPE_PROMISCUOUS BIT(4)
-#define P54_FILTER_TYPE_HIBERNATE BIT(5)
-#define P54_FILTER_TYPE_NOACK BIT(6)
-#define P54_FILTER_TYPE_RX_DISABLED BIT(7)
-
-struct p54_setup_mac {
- __le16 mac_mode;
- u8 mac_addr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- u8 rx_antenna;
- u8 rx_align;
- union {
- struct {
- __le32 basic_rate_mask;
- u8 rts_rates[8];
- __le32 rx_addr;
- __le16 max_rx;
- __le16 rxhw;
- __le16 wakeup_timer;
- __le16 unalloc0;
- } v1 __attribute__ ((packed));
- struct {
- __le32 rx_addr;
- __le16 max_rx;
- __le16 rxhw;
- __le16 timer;
- __le16 truncate;
- __le32 basic_rate_mask;
- u8 sbss_offset;
- u8 mcast_window;
- u8 rx_rssi_threshold;
- u8 rx_ed_threshold;
- __le32 ref_clock;
- __le16 lpf_bandwidth;
- __le16 osc_start_delay;
- } v2 __attribute__ ((packed));
- } __attribute__ ((packed));
-} __attribute__ ((packed));
-
-#define P54_SETUP_V1_LEN 40
-#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
-
-#define P54_SCAN_EXIT BIT(0)
-#define P54_SCAN_TRAP BIT(1)
-#define P54_SCAN_ACTIVE BIT(2)
-#define P54_SCAN_FILTER BIT(3)
-
-struct p54_scan_head {
- __le16 mode;
- __le16 dwell;
- u8 scan_params[20];
- __le16 freq;
-} __attribute__ ((packed));
-
-struct p54_scan_body {
- u8 pa_points_per_curve;
- u8 val_barker;
- u8 val_bpsk;
- u8 val_qpsk;
- u8 val_16qam;
- u8 val_64qam;
- struct p54_pa_curve_data_sample curve_data[8];
- u8 dup_bpsk;
- u8 dup_qpsk;
- u8 dup_16qam;
- u8 dup_64qam;
-} __attribute__ ((packed));
-
-struct p54_scan_body_longbow {
- struct p54_channel_output_limit_longbow power_limits;
- struct p54_pa_curve_data_sample_longbow curve_data[8];
- __le16 unkn[6]; /* maybe more power_limits or rate_mask */
-} __attribute__ ((packed));
-
-union p54_scan_body_union {
- struct p54_scan_body normal;
- struct p54_scan_body_longbow longbow;
-} __attribute__ ((packed));
-
-struct p54_scan_tail_rate {
- __le32 basic_rate_mask;
- u8 rts_rates[8];
-} __attribute__ ((packed));
-
-struct p54_led {
- __le16 flags;
- __le16 mask[2];
- __le16 delay[2];
-} __attribute__ ((packed));
-
-struct p54_edcf {
- u8 flags;
- u8 slottime;
- u8 sifs;
- u8 eofpad;
- struct p54_edcf_queue_param queue[8];
- u8 mapping[4];
- __le16 frameburst;
- __le16 round_trip_delay;
-} __attribute__ ((packed));
-
-struct p54_statistics {
- __le32 rx_success;
- __le32 rx_bad_fcs;
- __le32 rx_abort;
- __le32 rx_abort_phy;
- __le32 rts_success;
- __le32 rts_fail;
- __le32 tsf32;
- __le32 airtime;
- __le32 noise;
- __le32 sample_noise[8];
- __le32 sample_cca;
- __le32 sample_tx;
-} __attribute__ ((packed));
-
-struct p54_xbow_synth {
- __le16 magic1;
- __le16 magic2;
- __le16 freq;
- u32 padding[5];
-} __attribute__ ((packed));
-
-struct p54_timer {
- __le32 interval;
-} __attribute__ ((packed));
-
-struct p54_keycache {
- u8 entry;
- u8 key_id;
- u8 mac[ETH_ALEN];
- u8 padding[2];
- u8 key_type;
- u8 key_len;
- u8 key[24];
-} __attribute__ ((packed));
-
-struct p54_burst {
- u8 flags;
- u8 queue;
- u8 backlog;
- u8 pad;
- __le16 durations[32];
-} __attribute__ ((packed));
-
-struct p54_psm_interval {
- __le16 interval;
- __le16 periods;
-} __attribute__ ((packed));
-
-#define P54_PSM_CAM 0
-#define P54_PSM BIT(0)
-#define P54_PSM_DTIM BIT(1)
-#define P54_PSM_MCBC BIT(2)
-#define P54_PSM_CHECKSUM BIT(3)
-#define P54_PSM_SKIP_MORE_DATA BIT(4)
-#define P54_PSM_BEACON_TIMEOUT BIT(5)
-#define P54_PSM_HFOSLEEP BIT(6)
-#define P54_PSM_AUTOSWITCH_SLEEP BIT(7)
-#define P54_PSM_LPIT BIT(8)
-#define P54_PSM_BF_UCAST_SKIP BIT(9)
-#define P54_PSM_BF_MCAST_SKIP BIT(10)
-
-struct p54_psm {
- __le16 mode;
- __le16 aid;
- struct p54_psm_interval intervals[4];
- u8 beacon_rssi_skip_max;
- u8 rssi_delta_threshold;
- u8 nr;
- u8 exclude[1];
-} __attribute__ ((packed));
-
-#define MC_FILTER_ADDRESS_NUM 4
-
-struct p54_group_address_table {
- __le16 filter_enable;
- __le16 num_address;
- u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
-} __attribute__ ((packed));
-
-struct p54_txcancel {
- __le32 req_id;
-} __attribute__ ((packed));
-
-struct p54_sta_unlock {
- u8 addr[ETH_ALEN];
- u16 padding;
-} __attribute__ ((packed));
-
-#define P54_TIM_CLEAR BIT(15)
-struct p54_tim {
- u8 count;
- u8 padding[3];
- __le16 entry[8];
-} __attribute__ ((packed));
-
-struct p54_cce_quiet {
- __le32 period;
-} __attribute__ ((packed));
-
-struct p54_bt_balancer {
- __le16 prio_thresh;
- __le16 acl_thresh;
-} __attribute__ ((packed));
-
-struct p54_arp_table {
- __le16 filter_enable;
- u8 ipv4_addr[4];
-} __attribute__ ((packed));
-
-#endif /* P54COMMON_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index b1610ea4bb3..d348c265e86 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -22,6 +22,7 @@
#include <net/mac80211.h>
#include "p54.h"
+#include "lmac.h"
#include "p54pci.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -564,7 +565,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_common:
release_firmware(priv->firmware);
- p54_free_common(dev);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@@ -573,7 +573,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
err_free_dev:
pci_set_drvdata(pdev, NULL);
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
err_free_reg:
pci_release_regions(pdev);
@@ -590,16 +590,15 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
if (!dev)
return;
- ieee80211_unregister_hw(dev);
+ p54_unregister_common(dev);
priv = dev->priv;
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
- p54_free_common(dev);
iounmap(priv->map);
pci_release_regions(pdev);
pci_disable_device(pdev);
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index 72c7dbd39d0..eef532987d0 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -34,7 +34,7 @@
#include "p54spi_eeprom.h"
#include "p54.h"
-#include "p54common.h"
+#include "lmac.h"
MODULE_FIRMWARE("3826.arm");
MODULE_ALIAS("stlc45xx");
@@ -111,15 +111,6 @@ static void p54spi_spi_write(struct p54s_priv *priv, u8 address,
spi_sync(priv->spi, &m);
}
-static u16 p54spi_read16(struct p54s_priv *priv, u8 addr)
-{
- __le16 val;
-
- p54spi_spi_read(priv, addr, &val, sizeof(val));
-
- return le16_to_cpu(val);
-}
-
static u32 p54spi_read32(struct p54s_priv *priv, u8 addr)
{
__le32 val;
@@ -139,37 +130,12 @@ static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val)
p54spi_spi_write(priv, addr, &val, sizeof(val));
}
-struct p54spi_spi_reg {
- u16 address; /* __le16 ? */
- u16 length;
- char *name;
-};
-
-static const struct p54spi_spi_reg p54spi_registers_array[] =
-{
- { SPI_ADRS_ARM_INTERRUPTS, 32, "ARM_INT " },
- { SPI_ADRS_ARM_INT_EN, 32, "ARM_INT_ENA " },
- { SPI_ADRS_HOST_INTERRUPTS, 32, "HOST_INT " },
- { SPI_ADRS_HOST_INT_EN, 32, "HOST_INT_ENA" },
- { SPI_ADRS_HOST_INT_ACK, 32, "HOST_INT_ACK" },
- { SPI_ADRS_GEN_PURP_1, 32, "GP1_COMM " },
- { SPI_ADRS_GEN_PURP_2, 32, "GP2_COMM " },
- { SPI_ADRS_DEV_CTRL_STAT, 32, "DEV_CTRL_STA" },
- { SPI_ADRS_DMA_DATA, 16, "DMA_DATA " },
- { SPI_ADRS_DMA_WRITE_CTRL, 16, "DMA_WR_CTRL " },
- { SPI_ADRS_DMA_WRITE_LEN, 16, "DMA_WR_LEN " },
- { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_WR_BASE " },
- { SPI_ADRS_DMA_READ_CTRL, 16, "DMA_RD_CTRL " },
- { SPI_ADRS_DMA_READ_LEN, 16, "DMA_RD_LEN " },
- { SPI_ADRS_DMA_WRITE_BASE, 32, "DMA_RD_BASE " }
-};
-
-static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
+static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits)
{
int i;
for (i = 0; i < 2000; i++) {
- __le32 buffer = p54spi_read32(priv, reg);
+ u32 buffer = p54spi_read32(priv, reg);
if ((buffer & bits) == bits)
return 1;
}
@@ -179,8 +145,7 @@ static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits)
static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
const void *buf, size_t len)
{
- if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL,
- cpu_to_le32(HOST_ALLOWED))) {
+ if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) {
dev_err(&priv->spi->dev, "spi_write_dma not allowed "
"to DMA write.\n");
return -EAGAIN;
@@ -333,7 +298,7 @@ static int p54spi_wakeup(struct p54s_priv *priv)
/* And wait for the READY interrupt */
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_READY))) {
+ SPI_HOST_INT_READY)) {
dev_err(&priv->spi->dev, "INT_READY timeout\n");
return -EBUSY;
}
@@ -444,7 +409,7 @@ static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
goto out;
if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
- cpu_to_le32(SPI_HOST_INT_WR_READY))) {
+ SPI_HOST_INT_WR_READY)) {
dev_err(&priv->spi->dev, "WR_READY timeout\n");
ret = -EAGAIN;
goto out;
@@ -713,7 +678,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
{
struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
- ieee80211_unregister_hw(priv->hw);
+ p54_unregister_common(priv->hw);
free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
@@ -724,7 +689,6 @@ static int __devexit p54spi_remove(struct spi_device *spi)
mutex_destroy(&priv->mutex);
p54_free_common(priv->hw);
- ieee80211_free_hw(priv->hw);
return 0;
}
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 0e877a104a8..e44460ff149 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -22,6 +22,7 @@
#include <net/mac80211.h>
#include "p54.h"
+#include "lmac.h"
#include "p54usb.h"
MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
@@ -245,8 +246,10 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!data_urb)
+ if (!data_urb) {
+ p54_free_skb(dev, skb);
return;
+ }
hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
@@ -268,27 +271,22 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
{
struct p54u_priv *priv = dev->priv;
- struct urb *int_urb, *data_urb;
+ struct urb *int_urb = NULL, *data_urb = NULL;
struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
- struct net2280_reg_write *reg;
- int err = 0;
+ struct net2280_reg_write *reg = NULL;
+ int err = -ENOMEM;
reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
if (!reg)
- return;
+ goto out;
int_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!int_urb) {
- kfree(reg);
- return;
- }
+ if (!int_urb)
+ goto out;
data_urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!data_urb) {
- kfree(reg);
- usb_free_urb(int_urb);
- return;
- }
+ if (!data_urb)
+ goto out;
reg->port = cpu_to_le16(NET2280_DEV_U32);
reg->addr = cpu_to_le32(P54U_DEV_BASE);
@@ -303,11 +301,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
p54u_tx_dummy_cb, dev);
/*
- * This flag triggers a code path in the USB subsystem that will
- * free what's inside the transfer_buffer after the callback routine
- * has completed.
+ * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
+ * free what is inside the transfer_buffer after the last reference to
+ * the int_urb is dropped.
*/
int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
+ reg = NULL;
usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
@@ -328,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
usb_unanchor_urb(data_urb);
goto out;
}
- out:
+out:
usb_free_urb(int_urb);
usb_free_urb(data_urb);
if (err) {
- skb_pull(skb, sizeof(*hdr));
+ kfree(reg);
p54_free_skb(dev, skb);
}
}
@@ -961,7 +960,7 @@ err_free_fw:
release_firmware(priv->fw);
err_free_dev:
- ieee80211_free_hw(dev);
+ p54_free_common(dev);
usb_set_intfdata(intf, NULL);
usb_put_dev(udev);
return err;
@@ -975,13 +974,12 @@ static void __devexit p54u_disconnect(struct usb_interface *intf)
if (!dev)
return;
- ieee80211_unregister_hw(dev);
+ p54_unregister_common(dev);
priv = dev->priv;
usb_put_dev(interface_to_usbdev(intf));
release_firmware(priv->fw);
p54_free_common(dev);
- ieee80211_free_hw(dev);
}
static int p54u_pre_reset(struct usb_interface *intf)
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
new file mode 100644
index 00000000000..0d589d68e54
--- /dev/null
+++ b/drivers/net/wireless/p54/txrx.c
@@ -0,0 +1,860 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+#ifdef P54_MM_DEBUG
+static void p54_dump_tx_queue(struct p54_common *priv)
+{
+ unsigned long flags;
+ struct ieee80211_tx_info *info;
+ struct p54_tx_info *range;
+ struct sk_buff *skb;
+ struct p54_hdr *hdr;
+ unsigned int i = 0;
+ u32 prev_addr;
+ u32 largest_hole = 0, free;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ printk(KERN_DEBUG "%s: / --- tx queue dump (%d entries) --- \n",
+ wiphy_name(priv->hw->wiphy), skb_queue_len(&priv->tx_queue));
+
+ prev_addr = priv->rx_start;
+ skb_queue_walk(&priv->tx_queue, skb) {
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ hdr = (void *) skb->data;
+
+ free = range->start_addr - prev_addr;
+ printk(KERN_DEBUG "%s: | [%02d] => [skb:%p skb_len:0x%04x "
+ "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
+ "mem:{start:%04x end:%04x, free:%d}]\n",
+ wiphy_name(priv->hw->wiphy), i++, skb, skb->len,
+ le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
+ le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
+ range->start_addr, range->end_addr, free);
+
+ prev_addr = range->end_addr;
+ largest_hole = max(largest_hole, free);
+ }
+ free = priv->rx_end - prev_addr;
+ largest_hole = max(largest_hole, free);
+ printk(KERN_DEBUG "%s: \\ --- [free: %d], largest free block: %d ---\n",
+ wiphy_name(priv->hw->wiphy), free, largest_hole);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+}
+#endif /* P54_MM_DEBUG */
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or
+ * p54_free_skb frees allocated areas.
+ */
+static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct sk_buff *entry, *target_skb = NULL;
+ struct ieee80211_tx_info *info;
+ struct p54_tx_info *range;
+ struct p54_hdr *data = (void *) skb->data;
+ unsigned long flags;
+ u32 last_addr = priv->rx_start;
+ u32 target_addr = priv->rx_start;
+ u16 len = priv->headroom + skb->len + priv->tailroom + 3;
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ len = (range->extra_len + len) & ~0x3;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) {
+ /*
+ * The tx_queue is now really full.
+ *
+ * TODO: check if the device has crashed and reset it.
+ */
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -EBUSY;
+ }
+
+ skb_queue_walk(&priv->tx_queue, entry) {
+ u32 hole_size;
+ info = IEEE80211_SKB_CB(entry);
+ range = (void *) info->rate_driver_data;
+ hole_size = range->start_addr - last_addr;
+
+ if (!target_skb && hole_size >= len) {
+ target_skb = entry->prev;
+ hole_size -= len;
+ target_addr = last_addr;
+ break;
+ }
+ last_addr = range->end_addr;
+ }
+ if (unlikely(!target_skb)) {
+ if (priv->rx_end - last_addr >= len) {
+ target_skb = priv->tx_queue.prev;
+ if (!skb_queue_empty(&priv->tx_queue)) {
+ info = IEEE80211_SKB_CB(target_skb);
+ range = (void *)info->rate_driver_data;
+ target_addr = range->end_addr;
+ }
+ } else {
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return -ENOSPC;
+ }
+ }
+
+ info = IEEE80211_SKB_CB(skb);
+ range = (void *) info->rate_driver_data;
+ range->start_addr = target_addr;
+ range->end_addr = target_addr + len;
+ data->req_id = cpu_to_le32(target_addr + priv->headroom);
+ if (IS_DATA_FRAME(skb) &&
+ unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
+ priv->beacon_req_id = data->req_id;
+
+ __skb_queue_after(&priv->tx_queue, target_skb, skb);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return 0;
+}
+
+static void p54_tx_pending(struct p54_common *priv)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ skb = skb_dequeue(&priv->tx_pending);
+ if (unlikely(!skb))
+ return ;
+
+ ret = p54_assign_address(priv, skb);
+ if (unlikely(ret))
+ skb_queue_head(&priv->tx_pending, skb);
+ else
+ priv->tx(priv->hw, skb);
+}
+
+static void p54_wake_queues(struct p54_common *priv)
+{
+ unsigned long flags;
+ unsigned int i;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ p54_tx_pending(priv);
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ for (i = 0; i < priv->hw->queues; i++) {
+ if (priv->tx_stats[i + P54_QUEUE_DATA].len <
+ priv->tx_stats[i + P54_QUEUE_DATA].limit)
+ ieee80211_wake_queue(priv->hw, i);
+ }
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+}
+
+static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
+ struct sk_buff *skb,
+ const u16 p54_queue)
+{
+ struct ieee80211_tx_queue_stats *queue;
+ unsigned long flags;
+
+ if (WARN_ON(p54_queue > P54_QUEUE_NUM))
+ return -EINVAL;
+
+ queue = &priv->tx_stats[p54_queue];
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+ return -ENOSPC;
+ }
+
+ queue->len++;
+ queue->count++;
+
+ if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) {
+ u16 ac_queue = p54_queue - P54_QUEUE_DATA;
+ ieee80211_stop_queue(priv->hw, ac_queue);
+ }
+
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+ return 0;
+}
+
+static void p54_tx_qos_accounting_free(struct p54_common *priv,
+ struct sk_buff *skb)
+{
+ if (IS_DATA_FRAME(skb)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_stats_lock, flags);
+ priv->tx_stats[GET_HW_QUEUE(skb)].len--;
+ spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+
+ if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
+ if (priv->beacon_req_id == GET_REQ_ID(skb)) {
+ /* this is the active beacon set anymore */
+ priv->beacon_req_id = 0;
+ }
+ complete(&priv->beacon_comp);
+ }
+ }
+ p54_wake_queues(priv);
+}
+
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ if (unlikely(!skb))
+ return ;
+
+ skb_unlink(skb, &priv->tx_queue);
+ p54_tx_qos_accounting_free(priv, skb);
+ dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL_GPL(p54_free_skb);
+
+static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
+ const __le32 req_id)
+{
+ struct sk_buff *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_queue.lock, flags);
+ skb_queue_walk(&priv->tx_queue, entry) {
+ struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+ if (hdr->req_id == req_id) {
+ __skb_unlink(entry, &priv->tx_queue);
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ p54_tx_qos_accounting_free(priv, entry);
+ return entry;
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+ return NULL;
+}
+
+void p54_tx(struct p54_common *priv, struct sk_buff *skb)
+{
+ skb_queue_tail(&priv->tx_pending, skb);
+ p54_tx_pending(priv);
+}
+
+static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
+{
+ int band = priv->hw->conf.channel->band;
+
+ if (priv->rxhw != 5)
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
+ else
+ /*
+ * TODO: find the correct formula
+ */
+ return ((rssi * priv->rssical_db[band].mul) / 64 +
+ priv->rssical_db[band].add) / 4;
+}
+
+/*
+ * Even if the firmware is capable of dealing with incoming traffic,
+ * while dozing, we have to prepared in case mac80211 uses PS-POLL
+ * to retrieve outstanding frames from our AP.
+ * (see comment in net/mac80211/mlme.c @ line 1993)
+ */
+static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+ struct ieee80211_tim_ie *tim_ie;
+ u8 *tim;
+ u8 tim_len;
+ bool new_psm;
+
+ /* only beacons have a TIM IE */
+ if (!ieee80211_is_beacon(hdr->frame_control))
+ return;
+
+ if (!priv->aid)
+ return;
+
+ /* only consider beacons from the associated BSSID */
+ if (compare_ether_addr(hdr->addr3, priv->bssid))
+ return;
+
+ tim = p54_find_ie(skb, WLAN_EID_TIM);
+ if (!tim)
+ return;
+
+ tim_len = tim[1];
+ tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+ new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
+ if (new_psm != priv->powersave_override) {
+ priv->powersave_override = new_psm;
+ p54_set_ps(priv);
+ }
+}
+
+static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+ u16 freq = le16_to_cpu(hdr->freq);
+ size_t header_len = sizeof(*hdr);
+ u32 tsf32;
+ u8 rate = hdr->rate & 0xf;
+
+ /*
+ * If the device is in a unspecified state we have to
+ * ignore all data frames. Else we could end up with a
+ * nasty crash.
+ */
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return 0;
+
+ if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
+ return 0;
+
+ if (hdr->decrypt_status == P54_DECRYPT_OK)
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+ if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
+ (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
+ rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
+ rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
+ rx_status->noise = priv->noise;
+ if (hdr->rate & 0x10)
+ rx_status->flag |= RX_FLAG_SHORTPRE;
+ if (priv->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
+ rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
+ else
+ rx_status->rate_idx = rate;
+
+ rx_status->freq = freq;
+ rx_status->band = priv->hw->conf.channel->band;
+ rx_status->antenna = hdr->antenna;
+
+ tsf32 = le32_to_cpu(hdr->tsf32);
+ if (tsf32 < priv->tsf_low32)
+ priv->tsf_high32++;
+ rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
+ priv->tsf_low32 = tsf32;
+
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ header_len += hdr->align[0];
+
+ skb_pull(skb, header_len);
+ skb_trim(skb, le16_to_cpu(hdr->len));
+ if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
+ p54_pspoll_workaround(priv, skb);
+
+ ieee80211_rx_irqsafe(priv->hw, skb);
+
+ queue_delayed_work(priv->hw->workqueue, &priv->work,
+ msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
+ return -1;
+}
+
+static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
+ struct ieee80211_tx_info *info;
+ struct p54_hdr *entry_hdr;
+ struct p54_tx_data *entry_data;
+ struct sk_buff *entry;
+ unsigned int pad = 0, frame_len;
+ int count, idx;
+
+ entry = p54_find_and_unlink_skb(priv, hdr->req_id);
+ if (unlikely(!entry))
+ return ;
+
+ frame_len = entry->len;
+ info = IEEE80211_SKB_CB(entry);
+ entry_hdr = (struct p54_hdr *) entry->data;
+ entry_data = (struct p54_tx_data *) entry_hdr->data;
+ priv->stats.dot11ACKFailureCount += payload->tries - 1;
+
+ /*
+ * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
+ * generated by the driver. Therefore tx_status is bogus
+ * and we don't want to confuse the mac80211 stack.
+ */
+ if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
+ dev_kfree_skb_any(entry);
+ return ;
+ }
+
+ /*
+ * Clear manually, ieee80211_tx_info_clear_status would
+ * clear the counts too and we need them.
+ */
+ memset(&info->status.ampdu_ack_len, 0,
+ sizeof(struct ieee80211_tx_info) -
+ offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
+ status.ampdu_ack_len) != 23);
+
+ if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+ pad = entry_data->align[0];
+
+ /* walk through the rates array and adjust the counts */
+ count = payload->tries;
+ for (idx = 0; idx < 4; idx++) {
+ if (count >= info->status.rates[idx].count) {
+ count -= info->status.rates[idx].count;
+ } else if (count > 0) {
+ info->status.rates[idx].count = count;
+ count = 0;
+ } else {
+ info->status.rates[idx].idx = -1;
+ info->status.rates[idx].count = 0;
+ }
+ }
+
+ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+ (!payload->status))
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ if (payload->status & P54_TX_PSM_CANCELLED)
+ info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ info->status.ack_signal = p54_rssi_to_dbm(priv,
+ (int)payload->ack_rssi);
+
+ /* Undo all changes to the frame. */
+ switch (entry_data->key_type) {
+ case P54_CRYPTO_TKIPMICHAEL: {
+ u8 *iv = (u8 *)(entry_data->align + pad +
+ entry_data->crypt_offset);
+
+ /* Restore the original TKIP IV. */
+ iv[2] = iv[0];
+ iv[0] = iv[1];
+ iv[1] = (iv[0] | 0x20) & 0x7f; /* WEPSeed - 8.3.2.2 */
+
+ frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
+ break;
+ }
+ case P54_CRYPTO_AESCCMP:
+ frame_len -= 8; /* remove CCMP_MIC */
+ break;
+ case P54_CRYPTO_WEP:
+ frame_len -= 4; /* remove WEP_ICV */
+ break;
+ }
+
+ skb_trim(entry, frame_len);
+ skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+ ieee80211_tx_status_irqsafe(priv->hw, entry);
+}
+
+static void p54_rx_eeprom_readback(struct p54_common *priv,
+ struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
+ struct sk_buff *tmp;
+
+ if (!priv->eeprom)
+ return ;
+
+ if (priv->fw_var >= 0x509) {
+ memcpy(priv->eeprom, eeprom->v2.data,
+ le16_to_cpu(eeprom->v2.len));
+ } else {
+ memcpy(priv->eeprom, eeprom->v1.data,
+ le16_to_cpu(eeprom->v1.len));
+ }
+
+ priv->eeprom = NULL;
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+ complete(&priv->eeprom_comp);
+}
+
+static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
+ struct sk_buff *tmp;
+ u32 tsf32;
+
+ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+ return ;
+
+ tsf32 = le32_to_cpu(stats->tsf32);
+ if (tsf32 < priv->tsf_low32)
+ priv->tsf_high32++;
+ priv->tsf_low32 = tsf32;
+
+ priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
+ priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
+ priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
+
+ priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
+
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+}
+
+static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+ struct p54_trap *trap = (struct p54_trap *) hdr->data;
+ u16 event = le16_to_cpu(trap->event);
+ u16 freq = le16_to_cpu(trap->frequency);
+
+ switch (event) {
+ case P54_TRAP_BEACON_TX:
+ break;
+ case P54_TRAP_RADAR:
+ printk(KERN_INFO "%s: radar (freq:%d MHz)\n",
+ wiphy_name(priv->hw->wiphy), freq);
+ break;
+ case P54_TRAP_NO_BEACON:
+ if (priv->vif)
+ ieee80211_beacon_loss(priv->vif);
+ break;
+ case P54_TRAP_SCAN:
+ break;
+ case P54_TRAP_TBTT:
+ break;
+ case P54_TRAP_TIMER:
+ break;
+ default:
+ printk(KERN_INFO "%s: received event:%x freq:%d\n",
+ wiphy_name(priv->hw->wiphy), event, freq);
+ break;
+ }
+}
+
+static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
+{
+ struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+
+ switch (le16_to_cpu(hdr->type)) {
+ case P54_CONTROL_TYPE_TXDONE:
+ p54_rx_frame_sent(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_TRAP:
+ p54_rx_trap(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_BBP:
+ break;
+ case P54_CONTROL_TYPE_STAT_READBACK:
+ p54_rx_stats(priv, skb);
+ break;
+ case P54_CONTROL_TYPE_EEPROM_READBACK:
+ p54_rx_eeprom_readback(priv, skb);
+ break;
+ default:
+ printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
+ wiphy_name(priv->hw->wiphy), le16_to_cpu(hdr->type));
+ break;
+ }
+ return 0;
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ u16 type = le16_to_cpu(*((__le16 *)skb->data));
+
+ if (type & P54_HDR_FLAG_CONTROL)
+ return p54_rx_control(priv, skb);
+ else
+ return p54_rx_data(priv, skb);
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
+ struct ieee80211_tx_info *info, u8 *queue,
+ u32 *extra_len, u16 *flags, u16 *aid,
+ bool *burst_possible)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (ieee80211_is_data_qos(hdr->frame_control))
+ *burst_possible = true;
+ else
+ *burst_possible = false;
+
+ if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
+ *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+ if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+ *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+ *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
+
+ switch (priv->mode) {
+ case NL80211_IFTYPE_MONITOR:
+ /*
+ * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
+ * every frame in promiscuous/monitor mode.
+ * see STSW45x0C LMAC API - page 12.
+ */
+ *aid = 0;
+ *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC;
+ break;
+ case NL80211_IFTYPE_STATION:
+ *aid = 1;
+ break;
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_MESH_POINT:
+ if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+ *aid = 0;
+ *queue = P54_QUEUE_CAB;
+ return;
+ }
+
+ if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+ if (ieee80211_is_probe_resp(hdr->frame_control)) {
+ *aid = 0;
+ *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+ P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+ return;
+ } else if (ieee80211_is_beacon(hdr->frame_control)) {
+ *aid = 0;
+
+ if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+ /*
+ * Injecting beacons on top of a AP is
+ * not a good idea... nevertheless,
+ * it should be doable.
+ */
+
+ return;
+ }
+
+ *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+ *queue = P54_QUEUE_BEACON;
+ *extra_len = IEEE80211_MAX_TIM_LEN;
+ return;
+ }
+ }
+
+ if (info->control.sta)
+ *aid = info->control.sta->aid;
+ break;
+ }
+}
+
+static u8 p54_convert_algo(enum ieee80211_key_alg alg)
+{
+ switch (alg) {
+ case ALG_WEP:
+ return P54_CRYPTO_WEP;
+ case ALG_TKIP:
+ return P54_CRYPTO_TKIPMICHAEL;
+ case ALG_CCMP:
+ return P54_CRYPTO_AESCCMP;
+ default:
+ return 0;
+ }
+}
+
+int p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+ struct p54_common *priv = dev->priv;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct p54_tx_info *p54info;
+ struct p54_hdr *hdr;
+ struct p54_tx_data *txhdr;
+ unsigned int padding, len, extra_len;
+ int i, j, ridx;
+ u16 hdr_flags = 0, aid = 0;
+ u8 rate, queue = 0, crypt_offset = 0;
+ u8 cts_rate = 0x20;
+ u8 rc_flags;
+ u8 calculated_tries[4];
+ u8 nrates = 0, nremaining = 8;
+ bool burst_allowed = false;
+
+ p54_tx_80211_header(priv, skb, info, &queue, &extra_len,
+ &hdr_flags, &aid, &burst_allowed);
+
+ if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
+ if (!IS_QOS_QUEUE(queue)) {
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ } else {
+ return NETDEV_TX_BUSY;
+ }
+ }
+
+ padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+ len = skb->len;
+
+ if (info->control.hw_key) {
+ crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ u8 *iv = (u8 *)(skb->data + crypt_offset);
+ /*
+ * The firmware excepts that the IV has to have
+ * this special format
+ */
+ iv[1] = iv[0];
+ iv[0] = iv[2];
+ iv[2] = 0;
+ }
+ }
+
+ txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
+ hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
+
+ if (padding)
+ hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
+ hdr->type = cpu_to_le16(aid);
+ hdr->rts_tries = info->control.rates[0].count;
+
+ /*
+ * we register the rates in perfect order, and
+ * RTS/CTS won't happen on 5 GHz
+ */
+ cts_rate = info->control.rts_cts_rate_idx;
+
+ memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
+
+ /* see how many rates got used */
+ for (i = 0; i < dev->max_rates; i++) {
+ if (info->control.rates[i].idx < 0)
+ break;
+ nrates++;
+ }
+
+ /* limit tries to 8/nrates per rate */
+ for (i = 0; i < nrates; i++) {
+ /*
+ * The magic expression here is equivalent to 8/nrates for
+ * all values that matter, but avoids division and jumps.
+ * Note that nrates can only take the values 1 through 4.
+ */
+ calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
+ info->control.rates[i].count);
+ nremaining -= calculated_tries[i];
+ }
+
+ /* if there are tries left, distribute from back to front */
+ for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
+ int tmp = info->control.rates[i].count - calculated_tries[i];
+
+ if (tmp <= 0)
+ continue;
+ /* RC requested more tries at this rate */
+
+ tmp = min_t(int, tmp, nremaining);
+ calculated_tries[i] += tmp;
+ nremaining -= tmp;
+ }
+
+ ridx = 0;
+ for (i = 0; i < nrates && ridx < 8; i++) {
+ /* we register the rates in perfect order */
+ rate = info->control.rates[i].idx;
+ if (info->band == IEEE80211_BAND_5GHZ)
+ rate += 4;
+
+ /* store the count we actually calculated for TX status */
+ info->control.rates[i].count = calculated_tries[i];
+
+ rc_flags = info->control.rates[i].flags;
+ if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+ rate |= 0x10;
+ cts_rate |= 0x10;
+ }
+ if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+ burst_allowed = false;
+ rate |= 0x40;
+ } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+ rate |= 0x20;
+ burst_allowed = false;
+ }
+ for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
+ txhdr->rateset[ridx] = rate;
+ ridx++;
+ }
+ }
+
+ if (burst_allowed)
+ hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST;
+
+ /* TODO: enable bursting */
+ hdr->flags = cpu_to_le16(hdr_flags);
+ hdr->tries = ridx;
+ txhdr->rts_rate_idx = 0;
+ if (info->control.hw_key) {
+ txhdr->key_type = p54_convert_algo(info->control.hw_key->alg);
+ txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
+ memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
+ if (info->control.hw_key->alg == ALG_TKIP) {
+ /* reserve space for the MIC key */
+ len += 8;
+ memcpy(skb_put(skb, 8), &(info->control.hw_key->key
+ [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
+ }
+ /* reserve some space for ICV */
+ len += info->control.hw_key->icv_len;
+ memset(skb_put(skb, info->control.hw_key->icv_len), 0,
+ info->control.hw_key->icv_len);
+ } else {
+ txhdr->key_type = 0;
+ txhdr->key_len = 0;
+ }
+ txhdr->crypt_offset = crypt_offset;
+ txhdr->hw_queue = queue;
+ txhdr->backlog = priv->tx_stats[queue].len - 1;
+ memset(txhdr->durations, 0, sizeof(txhdr->durations));
+ txhdr->tx_antenna = ((info->antenna_sel_tx == 0) ?
+ 2 : info->antenna_sel_tx - 1) & priv->tx_diversity_mask;
+ if (priv->rxhw == 5) {
+ txhdr->longbow.cts_rate = cts_rate;
+ txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
+ } else {
+ txhdr->normal.output_power = priv->output_power;
+ txhdr->normal.cts_rate = cts_rate;
+ }
+ if (padding)
+ txhdr->align[0] = padding;
+
+ hdr->len = cpu_to_le16(len);
+ /* modifies skb->cb and with it info, so must be last! */
+ p54info = (void *) info->rate_driver_data;
+ p54info->extra_len = extra_len;
+
+ p54_tx(priv, skb);
+ return NETDEV_TX_OK;
+}
diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
index 8f621099344..c255d9c6a5f 100644
--- a/drivers/net/wireless/prism54/islpci_eth.c
+++ b/drivers/net/wireless/prism54/islpci_eth.c
@@ -234,7 +234,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
/* unlock the driver code */
spin_unlock_irqrestore(&priv->slock, flags);
- return 0;
+ return NETDEV_TX_OK;
drop_free:
ndev->stats.tx_dropped++;
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 30876728d7e..83d366258c8 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -49,9 +49,7 @@ static const struct pci_device_id prism54_id_tbl[] = {
/* 3COM 3CRWE154G72 Wireless LAN adapter */
{
- 0x10b7, 0x6001,
- PCI_ANY_ID, PCI_ANY_ID,
- 0, 0, 0
+ PCI_VDEVICE(3COM, 0x6001), 0
},
/* Intersil PRISM Indigo Wireless LAN adapter */
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index b10b0383dfa..64e574c3655 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -937,7 +937,7 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
@@ -951,9 +951,9 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
default:
dev->trans_start = jiffies;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
- return 0;
+ return NETDEV_TX_OK;
} /* ray_dev_start_xmit */
/*===========================================================================*/
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 3bec3dbd345..09c0702ae64 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -139,9 +139,15 @@ MODULE_PARM_DESC(workaround_interval,
/* Assume that Broadcom 4320 (only chipset at time of writing known to be
* based on wireless rndis) has default txpower of 13dBm.
* This value is from Linksys WUSB54GSC User Guide, Appendix F: Specifications.
- * 13dBm == 19.9mW
+ * 100% : 20 mW ~ 13dBm
+ * 75% : 15 mW ~ 12dBm
+ * 50% : 10 mW ~ 10dBm
+ * 25% : 5 mW ~ 7dBm
*/
-#define BCM4320_DEFAULT_TXPOWER 20
+#define BCM4320_DEFAULT_TXPOWER_DBM_100 13
+#define BCM4320_DEFAULT_TXPOWER_DBM_75 12
+#define BCM4320_DEFAULT_TXPOWER_DBM_50 10
+#define BCM4320_DEFAULT_TXPOWER_DBM_25 7
/* codes for "status" field of completion messages */
@@ -420,21 +426,30 @@ struct rndis_wlan_private {
/*
* cfg80211 ops
*/
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params);
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request);
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+ int dbm);
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
+
static struct cfg80211_ops rndis_config_ops = {
.change_virtual_intf = rndis_change_virtual_intf,
.scan = rndis_scan,
+ .set_wiphy_params = rndis_set_wiphy_params,
+ .set_tx_power = rndis_set_tx_power,
+ .get_tx_power = rndis_get_tx_power,
};
static void *rndis_wiphy_privid = &rndis_wiphy_privid;
-static const int bcm4320_power_output[4] = { 25, 50, 75, 100 };
static const unsigned char zero_bssid[ETH_ALEN] = {0,};
static const unsigned char ffff_bssid[ETH_ALEN] = { 0xff, 0xff, 0xff,
@@ -447,10 +462,19 @@ static struct rndis_wlan_private *get_rndis_wlan_priv(struct usbnet *dev)
}
-static u32 get_bcm4320_power(struct rndis_wlan_private *priv)
+static u32 get_bcm4320_power_dbm(struct rndis_wlan_private *priv)
{
- return BCM4320_DEFAULT_TXPOWER *
- bcm4320_power_output[priv->param_power_output] / 100;
+ switch (priv->param_power_output) {
+ default:
+ case 3:
+ return BCM4320_DEFAULT_TXPOWER_DBM_100;
+ case 2:
+ return BCM4320_DEFAULT_TXPOWER_DBM_75;
+ case 1:
+ return BCM4320_DEFAULT_TXPOWER_DBM_50;
+ case 0:
+ return BCM4320_DEFAULT_TXPOWER_DBM_25;
+ }
}
@@ -968,6 +992,36 @@ static int set_infra_mode(struct usbnet *usbdev, int mode)
}
+static int set_rts_threshold(struct usbnet *usbdev, u32 rts_threshold)
+{
+ __le32 tmp;
+
+ devdbg(usbdev, "set_rts_threshold %i", rts_threshold);
+
+ if (rts_threshold < 0 || rts_threshold > 2347)
+ rts_threshold = 2347;
+
+ tmp = cpu_to_le32(rts_threshold);
+ return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
+ sizeof(tmp));
+}
+
+
+static int set_frag_threshold(struct usbnet *usbdev, u32 frag_threshold)
+{
+ __le32 tmp;
+
+ devdbg(usbdev, "set_frag_threshold %i", frag_threshold);
+
+ if (frag_threshold < 256 || frag_threshold > 2346)
+ frag_threshold = 2346;
+
+ tmp = cpu_to_le32(frag_threshold);
+ return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
+ sizeof(tmp));
+}
+
+
static void set_default_iw_params(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
@@ -1222,20 +1276,14 @@ static void set_multicast_list(struct usbnet *usbdev)
/*
* cfg80211 ops
*/
-static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
+static int rndis_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- struct net_device *dev;
- struct usbnet *usbdev;
+ struct usbnet *usbdev = netdev_priv(dev);
int mode;
- /* we're under RTNL */
- dev = __dev_get_by_index(&init_net, ifindex);
- if (!dev)
- return -ENODEV;
- usbdev = netdev_priv(dev);
-
switch (type) {
case NL80211_IFTYPE_ADHOC:
mode = NDIS_80211_INFRA_ADHOC;
@@ -1251,6 +1299,64 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, int ifindex,
}
+static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+ int err;
+
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ err = set_frag_threshold(usbdev, wiphy->frag_threshold);
+ if (err < 0)
+ return err;
+ }
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ err = set_rts_threshold(usbdev, wiphy->rts_threshold);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+
+static int rndis_set_tx_power(struct wiphy *wiphy, enum tx_power_setting type,
+ int dbm)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+
+ devdbg(usbdev, "rndis_set_tx_power type:0x%x dbm:%i", type, dbm);
+
+ /* Device doesn't support changing txpower after initialization, only
+ * turn off/on radio. Support 'auto' mode and setting same dBm that is
+ * currently used.
+ */
+ if (type == TX_POWER_AUTOMATIC || dbm == get_bcm4320_power_dbm(priv)) {
+ if (!priv->radio_on)
+ disassociate(usbdev, 1); /* turn on radio */
+
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+
+static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
+{
+ struct rndis_wlan_private *priv = wiphy_priv(wiphy);
+ struct usbnet *usbdev = priv->usbdev;
+
+ *dbm = get_bcm4320_power_dbm(priv);
+
+ devdbg(usbdev, "rndis_get_tx_power dbm:%i", *dbm);
+
+ return 0;
+}
+
+
#define SCAN_DELAY_JIFFIES (HZ)
static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_scan_request *request)
@@ -1766,74 +1872,6 @@ static int rndis_iw_get_genie(struct net_device *dev,
}
-static int rndis_iw_set_rts(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- devdbg(usbdev, "SIOCSIWRTS");
-
- tmp = cpu_to_le32(wrqu->rts.value);
- return rndis_set_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp,
- sizeof(tmp));
-}
-
-
-static int rndis_iw_get_rts(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int len, ret;
-
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_802_11_RTS_THRESHOLD, &tmp, &len);
- if (ret == 0) {
- wrqu->rts.value = le32_to_cpu(tmp);
- wrqu->rts.flags = 1;
- wrqu->rts.disabled = 0;
- }
-
- devdbg(usbdev, "SIOCGIWRTS: %d", wrqu->rts.value);
-
- return ret;
-}
-
-
-static int rndis_iw_set_frag(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
-
- devdbg(usbdev, "SIOCSIWFRAG");
-
- tmp = cpu_to_le32(wrqu->frag.value);
- return rndis_set_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
- sizeof(tmp));
-}
-
-
-static int rndis_iw_get_frag(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- __le32 tmp;
- int len, ret;
-
- len = sizeof(tmp);
- ret = rndis_query_oid(usbdev, OID_802_11_FRAGMENTATION_THRESHOLD, &tmp,
- &len);
- if (ret == 0) {
- wrqu->frag.value = le32_to_cpu(tmp);
- wrqu->frag.flags = 1;
- wrqu->frag.disabled = 0;
- }
- devdbg(usbdev, "SIOCGIWFRAG: %d", wrqu->frag.value);
- return ret;
-}
-
-
static int rndis_iw_set_freq(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -1882,71 +1920,6 @@ static int rndis_iw_get_freq(struct net_device *dev,
}
-static int rndis_iw_get_txpower(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tx_power;
-
- if (priv->radio_on) {
- /* fake since changing tx_power (by userlevel) not supported */
- tx_power = cpu_to_le32(get_bcm4320_power(priv));
-
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- wrqu->txpower.value = le32_to_cpu(tx_power);
- wrqu->txpower.disabled = 0;
- } else {
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- wrqu->txpower.value = 0;
- wrqu->txpower.disabled = 1;
- }
-
- devdbg(usbdev, "SIOCGIWTXPOW: %d", wrqu->txpower.value);
-
- return 0;
-}
-
-
-static int rndis_iw_set_txpower(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct usbnet *usbdev = netdev_priv(dev);
- struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- __le32 tx_power = 0;
-
- if (!wrqu->txpower.disabled) {
- if (wrqu->txpower.flags == IW_TXPOW_MWATT)
- tx_power = cpu_to_le32(wrqu->txpower.value);
- else { /* wrqu->txpower.flags == IW_TXPOW_DBM */
- if (wrqu->txpower.value > 20)
- tx_power = cpu_to_le32(128);
- else if (wrqu->txpower.value < -43)
- tx_power = cpu_to_le32(127);
- else {
- signed char tmp;
- tmp = wrqu->txpower.value;
- tmp = -12 - tmp;
- tmp <<= 2;
- tx_power = cpu_to_le32((unsigned char)tmp);
- }
- }
- }
-
- devdbg(usbdev, "SIOCSIWTXPOW: %d", le32_to_cpu(tx_power));
-
- if (le32_to_cpu(tx_power) != 0) {
- /* txpower unsupported, just turn radio on */
- if (!priv->radio_on)
- return disassociate(usbdev, 1);
- return 0; /* all ready on */
- }
-
- /* tx_power == 0, turn off radio */
- return disassociate(usbdev, 0);
-}
-
-
static int rndis_iw_get_rate(struct net_device *dev,
struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
{
@@ -2022,12 +1995,12 @@ static const iw_handler rndis_iw_handler[] =
IW_IOCTL(SIOCSIWESSID) = rndis_iw_set_essid,
IW_IOCTL(SIOCGIWESSID) = rndis_iw_get_essid,
IW_IOCTL(SIOCGIWRATE) = rndis_iw_get_rate,
- IW_IOCTL(SIOCSIWRTS) = rndis_iw_set_rts,
- IW_IOCTL(SIOCGIWRTS) = rndis_iw_get_rts,
- IW_IOCTL(SIOCSIWFRAG) = rndis_iw_set_frag,
- IW_IOCTL(SIOCGIWFRAG) = rndis_iw_get_frag,
- IW_IOCTL(SIOCSIWTXPOW) = rndis_iw_set_txpower,
- IW_IOCTL(SIOCGIWTXPOW) = rndis_iw_get_txpower,
+ IW_IOCTL(SIOCSIWRTS) = (iw_handler) cfg80211_wext_siwrts,
+ IW_IOCTL(SIOCGIWRTS) = (iw_handler) cfg80211_wext_giwrts,
+ IW_IOCTL(SIOCSIWFRAG) = (iw_handler) cfg80211_wext_siwfrag,
+ IW_IOCTL(SIOCGIWFRAG) = (iw_handler) cfg80211_wext_giwfrag,
+ IW_IOCTL(SIOCSIWTXPOW) = (iw_handler) cfg80211_wext_siwtxpower,
+ IW_IOCTL(SIOCGIWTXPOW) = (iw_handler) cfg80211_wext_giwtxpower,
IW_IOCTL(SIOCSIWENCODE) = rndis_iw_set_encode,
IW_IOCTL(SIOCSIWENCODEEXT) = rndis_iw_set_encode_ext,
IW_IOCTL(SIOCSIWAUTH) = rndis_iw_set_auth,
@@ -2475,6 +2448,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf)
set_default_iw_params(usbdev);
+ /* set default rts/frag */
+ rndis_set_wiphy_params(wiphy,
+ WIPHY_PARAM_FRAG_THRESHOLD | WIPHY_PARAM_RTS_THRESHOLD);
+
/* turn radio on */
priv->radio_on = 1;
disassociate(usbdev, 1);
@@ -2522,10 +2499,18 @@ static void rndis_wlan_unbind(struct usbnet *usbdev, struct usb_interface *intf)
static int rndis_wlan_reset(struct usbnet *usbdev)
{
+ devdbg(usbdev, "rndis_wlan_reset");
return deauthenticate(usbdev);
}
+static int rndis_wlan_stop(struct usbnet *usbdev)
+{
+ devdbg(usbdev, "rndis_wlan_stop");
+ return disassociate(usbdev, 0);
+}
+
+
static const struct driver_info bcm4320b_info = {
.description = "Wireless RNDIS device, BCM4320b based",
.flags = FLAG_WLAN | FLAG_FRAMING_RN | FLAG_NO_SETINT,
@@ -2535,6 +2520,7 @@ static const struct driver_info bcm4320b_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320b_early_init,
.link_change = rndis_wlan_link_change,
};
@@ -2548,6 +2534,7 @@ static const struct driver_info bcm4320a_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.link_change = rndis_wlan_link_change,
};
@@ -2561,6 +2548,7 @@ static const struct driver_info rndis_wlan_info = {
.rx_fixup = rndis_rx_fixup,
.tx_fixup = rndis_tx_fixup,
.reset = rndis_wlan_reset,
+ .stop = rndis_wlan_stop,
.early_init = bcm4320a_early_init,
.link_change = rndis_wlan_link_change,
};
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 8aab3e6754b..f970aa25326 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -112,14 +112,6 @@ config RT2X00_LIB_FIRMWARE
config RT2X00_LIB_CRYPTO
boolean
-config RT2X00_LIB_RFKILL
- boolean
- default y if (RT2X00_LIB=y && INPUT=y) || (RT2X00_LIB=m && INPUT!=n)
- select INPUT_POLLDEV
-
-comment "rt2x00 rfkill support disabled due to modularized INPUT and built-in rt2x00"
- depends on RT2X00_LIB=y && INPUT=m
-
config RT2X00_LIB_LEDS
boolean
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index bfc7226f0af..13043ea9766 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -5,7 +5,6 @@ rt2x00lib-y += rt2x00queue.o
rt2x00lib-y += rt2x00link.o
rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
-rt2x00lib-$(CONFIG_RT2X00_LIB_RFKILL) += rt2x00rfkill.o
rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 435f945fe64..30185ad28d9 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2400pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -207,9 +206,6 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_BIT0);
}
-#else
-#define rt2400pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2400pci_brightness_set(struct led_classdev *led_cdev,
@@ -1391,10 +1387,8 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be enabled.
@@ -1567,12 +1561,14 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2400pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2400pci_get_tsf,
.tx_last_beacon = rt2400pci_tx_last_beacon,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
index ec3b004ddc3..ccd644104ad 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.h
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -928,7 +928,7 @@
#define RXD_W7_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
* NOTE: Logics in rt2400pci for txpower are reversed
* compared to the other rt2x00 drivers. A higher txpower
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 08b30d01e67..3b3171578b1 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -199,7 +199,6 @@ static const struct rt2x00debug rt2500pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -207,9 +206,6 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
return rt2x00_get_field32(reg, GPIOCSR_BIT0);
}
-#else
-#define rt2500pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2500pci_brightness_set(struct led_classdev *led_cdev,
@@ -1548,10 +1544,8 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be enabled.
@@ -1866,12 +1860,14 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2500pci_get_tsf,
.tx_last_beacon = rt2500pci_tx_last_beacon,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
index ce2f065c748..54d37957883 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.h
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -1218,7 +1218,7 @@
#define RXD_W10_DROP FIELD32(0x00000001)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index ce75426764a..de48c5c68ef 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -277,7 +277,6 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u16 reg;
@@ -285,9 +284,6 @@ static int rt2500usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2500usb_register_read(rt2x00dev, MAC_CSR19, &reg);
return rt2x00_get_field32(reg, MAC_CSR19_BIT7);
}
-#else
-#define rt2500usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2500usb_brightness_set(struct led_classdev *led_cdev,
@@ -1603,10 +1599,8 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Check if the BBP tuning should be disabled.
@@ -1902,11 +1896,13 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt2x00mac_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
index 5bc46fe7217..b01edca4258 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.h
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -831,7 +831,7 @@
#define RXD_W3_EIV FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 37561667925..9efb4171050 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -264,7 +264,6 @@ static const struct rt2x00debug rt2800usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -272,9 +271,6 @@ static int rt2800usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2);
}
-#else
-#define rt2800usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt2800usb_brightness_set(struct led_classdev *led_cdev,
@@ -1914,7 +1910,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* Before the radio can be enabled, the device first has
* to be woken up. After that it needs a bit of time
- * to be fully awake and the radio can be enabled.
+ * to be fully awake and then the radio can be enabled.
*/
rt2800usb_set_state(rt2x00dev, STATE_AWAKE);
msleep(1);
@@ -1922,7 +1918,7 @@ static int rt2800usb_set_device_state(struct rt2x00_dev *rt2x00dev,
break;
case STATE_RADIO_OFF:
/*
- * After the radio has been disablee, the device should
+ * After the radio has been disabled, the device should
* be put to sleep for powersaving.
*/
rt2800usb_disable_radio(rt2x00dev);
@@ -2224,10 +2220,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
*/
mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
if (!is_valid_ether_addr(mac)) {
- DECLARE_MAC_BUF(macbuf);
-
random_ether_addr(mac);
- EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+ EEPROM(rt2x00dev, "MAC: %pM\n", mac);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
@@ -2385,10 +2379,8 @@ static int rt2800usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_NIC_HW_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Store led settings, for correct led behaviour.
@@ -2792,6 +2784,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.get_tkip_seq = rt2800usb_get_tkip_seq,
@@ -2800,6 +2793,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.conf_tx = rt2800usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt2800usb_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 61a8be61d3f..2d9dc378336 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -1921,7 +1921,7 @@ struct mac_iveiv_entry {
#define RXWI_W3_SNR1 FIELD32(0x0000ff00)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_G_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index a498dde024e..cbec91ef6f7 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -245,7 +245,7 @@ struct link_ant {
struct antenna_setup active;
/*
- * RSSI information for the different antenna's.
+ * RSSI information for the different antennas.
* These statistics are used to determine when
* to switch antenna when using software diversity.
*
@@ -594,7 +594,6 @@ enum rt2x00_flags {
DEVICE_STATE_INITIALIZED,
DEVICE_STATE_STARTED,
DEVICE_STATE_ENABLED_RADIO,
- DEVICE_STATE_DISABLED_RADIO_HW,
/*
* Driver requirements
@@ -634,7 +633,7 @@ struct rt2x00_dev {
* The structure stored in here depends on the
* system bus (PCI or USB).
* When accessing this variable, the rt2x00dev_{pci,usb}
- * macro's should be used for correct typecasting.
+ * macros should be used for correct typecasting.
*/
struct device *dev;
@@ -651,18 +650,6 @@ struct rt2x00_dev {
enum ieee80211_band curr_band;
/*
- * rfkill structure for RF state switching support.
- * This will only be compiled in when required.
- */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
- unsigned long rfkill_state;
-#define RFKILL_STATE_ALLOCATED 1
-#define RFKILL_STATE_REGISTERED 2
-#define RFKILL_STATE_BLOCKED 3
- struct input_polled_dev *rfkill_poll_dev;
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
- /*
* If enabled, the debugfs interface structures
* required for deregistration of debugfs.
*/
@@ -975,6 +962,8 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
int mc_count, struct dev_addr_list *mc_list);
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
@@ -992,6 +981,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
u32 changes);
int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
/*
* Driver allocation handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 3e019a12df2..c6e0bcf78e9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -132,7 +132,7 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
/*
* Failsafe: Make sure we are not sending the
* ANTENNA_SW_DIVERSITY state to the driver.
- * If that happes fallback to hardware default,
+ * If that happens, fallback to hardware defaults,
* or our own default.
* The calls to rt2x00lib_config_antenna_check()
* might have caused that we restore back to the already
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index bc4e81e2184..30fbd3bbe08 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -53,8 +53,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
- !hw_key || entry->skb->do_not_encrypt)
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key)
return;
__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
@@ -82,8 +81,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct ieee80211_key_conf *key = tx_info->control.hw_key;
unsigned int overhead = 0;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) ||
- !key || skb->do_not_encrypt)
+ if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key)
return overhead;
/*
@@ -131,7 +129,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, struct txentry_desc *txdesc)
/* Pull buffer to correct size */
skb_pull(skb, txdesc->iv_len);
- /* IV/EIV data has officially be stripped */
+ /* IV/EIV data has officially been stripped */
skbdesc->flags |= SKBDESC_IV_STRIPPED;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 57813e72c80..658a63bfb76 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -40,8 +40,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
* Don't enable the radio twice.
* And check if the hardware button has been disabled.
*/
- if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags) ||
- test_bit(DEVICE_STATE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+ if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
return 0;
/*
@@ -449,7 +448,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
* mac80211 will clean up the skb structure.
*/
rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb);
- ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb, rx_status);
+ memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status));
+ ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb);
/*
* Replace the skb with the freshly allocated one.
@@ -870,7 +870,6 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
*/
rt2x00link_register(rt2x00dev);
rt2x00leds_register(rt2x00dev);
- rt2x00rfkill_allocate(rt2x00dev);
rt2x00debug_register(rt2x00dev);
set_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
@@ -902,7 +901,6 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
* Free extra components
*/
rt2x00debug_deregister(rt2x00dev);
- rt2x00rfkill_free(rt2x00dev);
rt2x00leds_unregister(rt2x00dev);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index 0bf2715fa93..512fa2bc3a1 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -30,10 +30,8 @@
/*
* Interval defines
- * Both the link tuner as the rfkill will be called once per second.
*/
#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ)
-#define RFKILL_POLL_INTERVAL 1000
/*
* rt2x00_rate: Per rate device information
@@ -386,29 +384,18 @@ static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
/*
* RFkill handlers.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
-#else
static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
{
+ if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
}
static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
{
+ if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
}
-static inline void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
-}
-
-static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
-}
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
-
/*
* LED handlers
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index eb9b981b913..32570758e67 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -158,7 +158,7 @@ static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
/*
* During the last period we have sampled the RSSI
- * from both antenna's. It now is time to determine
+ * from both antennas. It now is time to determine
* which antenna demonstrated the best performance.
* When we are already on the antenna with the best
* performance, then there really is nothing for us
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c4c06b4e1f0..9d31c23b92f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -73,7 +73,8 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
else
rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
- skb->do_not_encrypt = 1;
+ /* Disable hardware encryption */
+ rts_info->control.hw_key = NULL;
/*
* RTS/CTS frame should use the length of the frame plus any
@@ -340,7 +341,7 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed)
int status;
/*
- * Mac80211 might be calling this function while we are trying
+ * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@@ -453,6 +454,16 @@ static void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len)
sizeof(crypto->rx_mic));
}
+int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ bool set)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+
+ rt2x00lib_beacondone(rt2x00dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_tim);
+
int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
@@ -576,7 +587,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw,
int update_bssid = 0;
/*
- * Mac80211 might be calling this function while we are trying
+ * mac80211 might be calling this function while we are trying
* to remove the device or perhaps suspending it.
*/
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
@@ -687,3 +698,12 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
+
+void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ bool blocked = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+
+ wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index b5e06347c8a..47d175a1379 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -29,7 +29,7 @@
#include <linux/prefetch.h>
/**
- * DOC: Entrie frame size
+ * DOC: Entry frame size
*
* Ralink PCI devices demand the Frame size to be a multiple of 128 bytes,
* for USB devices this restriction does not apply, but the value of
@@ -45,13 +45,13 @@
/**
* DOC: Number of entries per queue
*
- * Under normal load without fragmentation 12 entries are sufficient
+ * Under normal load without fragmentation, 12 entries are sufficient
* without the queue being filled up to the maximum. When using fragmentation
- * and the queue threshold code we need to add some additional margins to
+ * and the queue threshold code, we need to add some additional margins to
* make sure the queue will never (or only under extreme load) fill up
* completely.
- * Since we don't use preallocated DMA having a large number of queue entries
- * will have only minimal impact on the memory requirements for the queue.
+ * Since we don't use preallocated DMA, having a large number of queue entries
+ * will have minimal impact on the memory requirements for the queue.
*/
#define RX_ENTRIES 24
#define TX_ENTRIES 24
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
index 861322d97fc..983e52e127a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00reg.h
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -176,8 +176,8 @@ struct rt2x00_field32 {
#define is_valid_mask(x) is_power_of_two(1LU + (x) + low_bit_mask(x))
/*
- * Macro's to find first set bit in a variable.
- * These macro's behaves the same as the __ffs() function with
+ * Macros to find first set bit in a variable.
+ * These macros behave the same as the __ffs() functions but
* the most important difference that this is done during
* compile-time rather then run-time.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
deleted file mode 100644
index b6d4c6700bf..00000000000
--- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- Copyright (C) 2004 - 2009 rt2x00 SourceForge Project
- <http://rt2x00.serialmonkey.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the
- Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- Module: rt2x00rfkill
- Abstract: rt2x00 rfkill routines.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "rt2x00.h"
-#include "rt2x00lib.h"
-
-static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
-{
- struct rt2x00_dev *rt2x00dev = poll_dev->private;
- int state, old_state;
-
- if (!test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state) ||
- !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
- return;
-
- /*
- * Poll latest state, if the state is different then the previous state,
- * we should generate an input event.
- */
- state = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
- old_state = !!test_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
-
- if (old_state != state) {
- input_report_switch(poll_dev->input, SW_RFKILL_ALL, state);
- change_bit(RFKILL_STATE_BLOCKED, &rt2x00dev->rfkill_state);
- }
-}
-
-void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
- return;
-
- if (input_register_polled_device(rt2x00dev->rfkill_poll_dev)) {
- ERROR(rt2x00dev, "Failed to register polled device.\n");
- return;
- }
-
- __set_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-
- /*
- * Force initial poll which will detect the initial device state,
- * and correctly sends the signal to the input layer about this
- * state.
- */
- rt2x00rfkill_poll(rt2x00dev->rfkill_poll_dev);
-}
-
-void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
-{
- if (!test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- !test_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state))
- return;
-
- input_unregister_polled_device(rt2x00dev->rfkill_poll_dev);
-
- __clear_bit(RFKILL_STATE_REGISTERED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
-{
- struct input_polled_dev *poll_dev;
-
- if (test_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state) ||
- !test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
- return;
-
- poll_dev = input_allocate_polled_device();
- if (!poll_dev) {
- ERROR(rt2x00dev, "Failed to allocate polled device.\n");
- return;
- }
-
- poll_dev->private = rt2x00dev;
- poll_dev->poll = rt2x00rfkill_poll;
- poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
-
- poll_dev->input->name = rt2x00dev->ops->name;
- poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy);
- poll_dev->input->id.bustype = BUS_HOST;
- poll_dev->input->id.vendor = 0x1814;
- poll_dev->input->id.product = rt2x00dev->chip.rt;
- poll_dev->input->id.version = rt2x00dev->chip.rev;
- poll_dev->input->dev.parent = wiphy_dev(rt2x00dev->hw->wiphy);
- poll_dev->input->evbit[0] = BIT(EV_SW);
- poll_dev->input->swbit[0] = BIT(SW_RFKILL_ALL);
-
- rt2x00dev->rfkill_poll_dev = poll_dev;
-
- __set_bit(RFKILL_STATE_ALLOCATED, &rt2x00dev->rfkill_state);
-}
-
-void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
-{
- if (!__test_and_clear_bit(RFKILL_STATE_ALLOCATED,
- &rt2x00dev->rfkill_state))
- return;
-
- input_free_polled_device(rt2x00dev->rfkill_poll_dev);
- rt2x00dev->rfkill_poll_dev = NULL;
-}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 49b29ff90c4..fb95b8cc4fe 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -237,7 +237,6 @@ static const struct rt2x00debug rt61pci_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -245,9 +244,6 @@ static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_BIT5);
}
-#else
-#define rt61pci_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt61pci_brightness_set(struct led_classdev *led_cdev,
@@ -2316,7 +2312,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
}
/*
- * Determine number of antenna's.
+ * Determine number of antennas.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
@@ -2338,10 +2334,8 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Read frequency offset and RF programming sequence.
@@ -2722,12 +2716,14 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt61pci_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt61pci_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index 6c71f77c816..93eb699165c 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -1476,7 +1476,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W15_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index c18848836f2..4f9b1772e1a 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -183,7 +183,6 @@ static const struct rt2x00debug rt73usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
-#ifdef CONFIG_RT2X00_LIB_RFKILL
static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -191,9 +190,6 @@ static int rt73usb_rfkill_poll(struct rt2x00_dev *rt2x00dev)
rt2x00usb_register_read(rt2x00dev, MAC_CSR13, &reg);
return rt2x00_get_field32(reg, MAC_CSR13_BIT7);
}
-#else
-#define rt73usb_rfkill_poll NULL
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
#ifdef CONFIG_RT2X00_LIB_LEDS
static void rt73usb_brightness_set(struct led_classdev *led_cdev,
@@ -1863,10 +1859,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Detect if this device has an hardware controlled radio.
*/
-#ifdef CONFIG_RT2X00_LIB_RFKILL
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
-#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* Read frequency offset.
@@ -2247,12 +2241,14 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.remove_interface = rt2x00mac_remove_interface,
.config = rt2x00mac_config,
.configure_filter = rt2x00mac_configure_filter,
+ .set_tim = rt2x00mac_set_tim,
.set_key = rt2x00mac_set_key,
.get_stats = rt2x00mac_get_stats,
.bss_info_changed = rt2x00mac_bss_info_changed,
.conf_tx = rt73usb_conf_tx,
.get_tx_stats = rt2x00mac_get_tx_stats,
.get_tsf = rt73usb_get_tsf,
+ .rfkill_poll = rt2x00mac_rfkill_poll,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index c8016f65b4b..81fe0be51c4 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -809,7 +809,7 @@ struct hw_pairwise_ta_entry {
/*
* EEPROM antenna.
- * ANTENNA_NUM: Number of antenna's.
+ * ANTENNA_NUM: Number of antennas.
* TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
* FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
@@ -1058,7 +1058,7 @@ struct hw_pairwise_ta_entry {
#define RXD_W5_RESERVED FIELD32(0xffffffff)
/*
- * Macro's for converting txpower from EEPROM to mac80211 value
+ * Macros for converting txpower from EEPROM to mac80211 value
* and from mac80211 value to register value.
*/
#define MIN_TXPOWER 0
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 7e65d7c3180..09f46abc730 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -143,7 +143,8 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
skb = new_skb;
priv->rx_buf[priv->rx_idx] = skb;
@@ -280,7 +281,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
(ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
remainder = (16 * (skb->len + 4)) %
((ieee80211_get_tx_rate(dev, info)->bitrate * 2) / 10);
- if (remainder > 0 && remainder <= 6)
+ if (remainder <= 6)
plcp_len |= 1 << 15;
}
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 294250e294d..c9b9dbe584c 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -380,7 +380,8 @@ static void rtl8187_rx_cb(struct urb *urb)
rx_status.flag |= RX_FLAG_TSFT;
if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
- ieee80211_rx_irqsafe(dev, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(dev, skb);
skb = dev_alloc_skb(RTL8187_MAX_RX);
if (unlikely(!skb)) {
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 38366a56b71..73300c226f6 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1582,7 +1582,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb)
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/*
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index ab7fc5c0c8b..5cb5329a20d 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -2891,7 +2891,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev)
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return 0;
+ return NETDEV_TX_OK;
}
/*********************** HARDWARE CONFIGURATION ***********************/
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 6af706408ac..9dd241adc37 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -3113,7 +3113,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
* able to detect collisions, therefore in theory we don't really
* need to pad. Jean II */
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
wv_packet_write(dev, skb->data, skb->len);
@@ -3122,7 +3122,7 @@ wavelan_packet_xmit(struct sk_buff * skb,
#ifdef DEBUG_TX_TRACE
printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
#endif
- return(0);
+ return NETDEV_TX_OK;
}
/********************** HARDWARE CONFIGURATION **********************/
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index a82c4cd436d..82a0f97975d 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -1,11 +1,18 @@
-config WL12XX
- tristate "TI wl1251/wl1271 support"
- depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL
+menuconfig WL12XX
+ boolean "TI wl12xx driver support"
+ depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+ ---help---
+ This will enable TI wl12xx driver support. The drivers make
+ use of the mac80211 stack.
+
+config WL1251
+ tristate "TI wl1251 support"
+ depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
select FW_LOADER
select CRC7
---help---
This module adds support for wireless adapters based on
- TI wl1251/wl1271 chipsets.
+ TI wl1251 chipset.
- If you choose to build a module, it'll be called wl12xx. Say N if
+ If you choose to build a module, it'll be called wl1251. Say N if
unsure.
diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile
index d43de27dc54..d5595a841f5 100644
--- a/drivers/net/wireless/wl12xx/Makefile
+++ b/drivers/net/wireless/wl12xx/Makefile
@@ -1,4 +1,5 @@
-wl12xx-objs = main.o spi.o event.o tx.o rx.o \
- ps.o cmd.o acx.o boot.o init.o wl1251.o \
- debugfs.o
-obj-$(CONFIG_WL12XX) += wl12xx.o
+wl1251-objs = wl1251_main.o wl1251_spi.o wl1251_event.o \
+ wl1251_tx.o wl1251_rx.o wl1251_ps.o wl1251_cmd.o \
+ wl1251_acx.o wl1251_boot.o wl1251_init.o \
+ wl1251_ops.o wl1251_debugfs.o
+obj-$(CONFIG_WL1251) += wl1251.o
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
deleted file mode 100644
index 1cfd458ad5a..00000000000
--- a/drivers/net/wireless/wl12xx/acx.c
+++ /dev/null
@@ -1,689 +0,0 @@
-#include "acx.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
- u8 mgt_rate, u8 mgt_mod)
-{
- int ret;
- struct acx_fw_gen_frame_rates rates;
-
- wl12xx_debug(DEBUG_ACX, "acx frame rates");
-
- rates.header.id = ACX_FW_GEN_FRAME_RATES;
- rates.header.len = sizeof(struct acx_fw_gen_frame_rates) -
- sizeof(struct acx_header);
-
- rates.tx_ctrl_frame_rate = ctrl_rate;
- rates.tx_ctrl_frame_mod = ctrl_mod;
- rates.tx_mgt_frame_rate = mgt_rate;
- rates.tx_mgt_frame_mod = mgt_mod;
-
- ret = wl12xx_cmd_configure(wl, &rates, sizeof(rates));
- if (ret < 0) {
- wl12xx_error("Failed to set FW rates and modulation");
- return ret;
- }
-
- return 0;
-}
-
-
-int wl12xx_acx_station_id(struct wl12xx *wl)
-{
- int ret, i;
- struct dot11_station_id mac;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_station_id");
-
- mac.header.id = DOT11_STATION_ID;
- mac.header.len = sizeof(mac) - sizeof(struct acx_header);
-
- for (i = 0; i < ETH_ALEN; i++)
- mac.mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
-
- ret = wl12xx_cmd_configure(wl, &mac, sizeof(mac));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id)
-{
- struct acx_dot11_default_key default_key;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
-
- default_key.header.id = DOT11_DEFAULT_KEY;
- default_key.header.len = sizeof(default_key) -
- sizeof(struct acx_header);
-
- default_key.id = key_id;
-
- ret = wl12xx_cmd_configure(wl, &default_key, sizeof(default_key));
- if (ret < 0) {
- wl12xx_error("Couldnt set default key");
- return ret;
- }
-
- wl->default_key = key_id;
-
- return 0;
-}
-
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval)
-{
- struct acx_wake_up_condition wake_up;
-
- wl12xx_debug(DEBUG_ACX, "acx wake up conditions");
-
- wake_up.header.id = ACX_WAKE_UP_CONDITIONS;
- wake_up.header.len = sizeof(wake_up) - sizeof(struct acx_header);
-
- wake_up.wake_up_event = WAKE_UP_EVENT_DTIM_BITMAP;
- wake_up.listen_interval = listen_interval;
-
- return wl12xx_cmd_configure(wl, &wake_up, sizeof(wake_up));
-}
-
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth)
-{
- int ret;
- struct acx_sleep_auth auth;
-
- wl12xx_debug(DEBUG_ACX, "acx sleep auth");
-
- auth.header.id = ACX_SLEEP_AUTH;
- auth.header.len = sizeof(auth) - sizeof(struct acx_header);
-
- auth.sleep_auth = sleep_auth;
-
- ret = wl12xx_cmd_configure(wl, &auth, sizeof(auth));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len)
-{
- struct wl12xx_command cmd;
- struct acx_revision *rev;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx fw rev");
-
- memset(&cmd, 0, sizeof(cmd));
-
- ret = wl12xx_cmd_interrogate(wl, ACX_FW_REV, sizeof(*rev), &cmd);
- if (ret < 0) {
- wl12xx_warning("ACX_FW_REV interrogate failed");
- return ret;
- }
-
- rev = (struct acx_revision *) &cmd.parameters;
-
- /* be careful with the buffer sizes */
- strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
-
- /*
- * if the firmware version string is exactly
- * sizeof(rev->fw_version) long or fw_len is less than
- * sizeof(rev->fw_version) it won't be null terminated
- */
- buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
-
- return 0;
-}
-
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power)
-{
- struct acx_current_tx_power ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
-
- if (power < 0 || power > 25)
- return -EINVAL;
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = DOT11_CUR_TX_PWR;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.current_tx_power = power * 10;
-
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("configure of tx power failed: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_feature_cfg(struct wl12xx *wl)
-{
- struct acx_feature_config feature;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx feature cfg");
-
- memset(&feature, 0, sizeof(feature));
-
- feature.header.id = ACX_FEATURE_CFG;
- feature.header.len = sizeof(feature) - sizeof(struct acx_header);
-
- /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
- feature.data_flow_options = 0;
- feature.options = 0;
-
- ret = wl12xx_cmd_configure(wl, &feature, sizeof(feature));
- if (ret < 0)
- wl12xx_error("Couldnt set HW encryption");
-
- return ret;
-}
-
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len)
-{
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx mem map");
-
- ret = wl12xx_cmd_interrogate(wl, ACX_MEM_MAP, len, &cmd);
- if (ret < 0)
- return ret;
- else if (cmd.status != CMD_STATUS_SUCCESS)
- return -EIO;
-
- memcpy(mem_map, &cmd.parameters, len);
-
- return 0;
-}
-
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
- struct acx_data_path_params_resp *data_path)
-{
- struct acx_data_path_params params;
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx data path params");
-
- params.rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
- params.tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
-
- params.rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
- params.tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
-
- params.tx_complete_threshold = 1;
-
- params.tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
-
- params.tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
-
- params.header.id = ACX_DATA_PATH_PARAMS;
- params.header.len = sizeof(params) - sizeof(struct acx_header);
-
- ret = wl12xx_cmd_configure(wl, &params, sizeof(params));
- if (ret < 0)
- return ret;
-
-
- ret = wl12xx_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
- sizeof(struct acx_data_path_params_resp),
- &cmd);
-
- if (ret < 0) {
- wl12xx_warning("failed to read data path parameters: %d", ret);
- return ret;
- } else if (cmd.status != CMD_STATUS_SUCCESS) {
- wl12xx_warning("data path parameter acx status failed");
- return -EIO;
- }
-
- memcpy(data_path, &cmd.parameters, sizeof(*data_path));
-
- return 0;
-}
-
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time)
-{
- struct rx_msdu_lifetime msdu_lifetime;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rx msdu life time");
-
- msdu_lifetime.header.id = DOT11_RX_MSDU_LIFE_TIME;
- msdu_lifetime.header.len = sizeof(msdu_lifetime) -
- sizeof(struct acx_header);
- msdu_lifetime.lifetime = life_time;
-
- ret = wl12xx_cmd_configure(wl, &msdu_lifetime, sizeof(msdu_lifetime));
- if (ret < 0) {
- wl12xx_warning("failed to set rx msdu life time: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter)
-{
- struct acx_rx_config rx_config;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rx config");
-
- rx_config.header.id = ACX_RX_CFG;
- rx_config.header.len = sizeof(rx_config) - sizeof(struct acx_header);
- rx_config.config_options = config;
- rx_config.filter_options = filter;
-
- ret = wl12xx_cmd_configure(wl, &rx_config, sizeof(rx_config));
- if (ret < 0) {
- wl12xx_warning("failed to set rx config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_pd_threshold(struct wl12xx *wl)
-{
- struct acx_packet_detection packet_detection;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx data pd threshold");
-
- /* FIXME: threshold value not set */
- packet_detection.header.id = ACX_PD_THRESHOLD;
- packet_detection.header.len = sizeof(packet_detection) -
- sizeof(struct acx_header);
-
- ret = wl12xx_cmd_configure(wl, &packet_detection,
- sizeof(packet_detection));
- if (ret < 0) {
- wl12xx_warning("failed to set pd threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time)
-{
- struct acx_slot slot;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx slot");
-
- slot.header.id = ACX_SLOT;
- slot.header.len = sizeof(slot) - sizeof(struct acx_header);
-
- slot.wone_index = STATION_WONE_INDEX;
- slot.slot_time = slot_time;
-
- ret = wl12xx_cmd_configure(wl, &slot, sizeof(slot));
- if (ret < 0) {
- wl12xx_warning("failed to set slot time: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl)
-{
- struct multicast_grp_addr_start multicast;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx group address tbl");
-
- /* MAC filtering */
- multicast.header.id = DOT11_GROUP_ADDRESS_TBL;
- multicast.header.len = sizeof(multicast) - sizeof(struct acx_header);
-
- multicast.enabled = 0;
- multicast.num_groups = 0;
- memset(multicast.mac_table, 0, ADDRESS_GROUP_MAX_LEN);
-
- ret = wl12xx_cmd_configure(wl, &multicast, sizeof(multicast));
- if (ret < 0) {
- wl12xx_warning("failed to set group addr table: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl)
-{
- struct acx_rx_timeout rx_timeout;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx service period timeout");
-
- /* RX timeout */
- rx_timeout.header.id = ACX_SERVICE_PERIOD_TIMEOUT;
- rx_timeout.header.len = sizeof(rx_timeout) - sizeof(struct acx_header);
-
- rx_timeout.ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
- rx_timeout.upsd_timeout = RX_TIMEOUT_UPSD_DEF;
-
- ret = wl12xx_cmd_configure(wl, &rx_timeout, sizeof(rx_timeout));
- if (ret < 0) {
- wl12xx_warning("failed to set service period timeout: %d",
- ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold)
-{
- struct acx_rts_threshold rts;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx rts threshold");
-
- rts.header.id = DOT11_RTS_THRESHOLD;
- rts.header.len = sizeof(rts) - sizeof(struct acx_header);
-
- rts.threshold = rts_threshold;
-
- ret = wl12xx_cmd_configure(wl, &rts, sizeof(rts));
- if (ret < 0) {
- wl12xx_warning("failed to set rts threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl)
-{
- struct acx_beacon_filter_option beacon_filter;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx beacon filter opt");
-
- beacon_filter.header.id = ACX_BEACON_FILTER_OPT;
- beacon_filter.header.len = sizeof(beacon_filter) -
- sizeof(struct acx_header);
-
- beacon_filter.enable = 0;
- beacon_filter.max_num_beacons = 0;
-
- ret = wl12xx_cmd_configure(wl, &beacon_filter, sizeof(beacon_filter));
- if (ret < 0) {
- wl12xx_warning("failed to set beacon filter opt: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl)
-{
- struct acx_beacon_filter_ie_table ie_table;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx beacon filter table");
-
- ie_table.header.id = ACX_BEACON_FILTER_TABLE;
- ie_table.header.len = sizeof(ie_table) - sizeof(struct acx_header);
-
- ie_table.num_ie = 0;
- memset(ie_table.table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
-
- ret = wl12xx_cmd_configure(wl, &ie_table, sizeof(ie_table));
- if (ret < 0) {
- wl12xx_warning("failed to set beacon filter table: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_sg_enable(struct wl12xx *wl)
-{
- struct acx_bt_wlan_coex pta;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx sg enable");
-
- pta.header.id = ACX_SG_ENABLE;
- pta.header.len = sizeof(pta) - sizeof(struct acx_header);
-
- pta.enable = SG_ENABLE;
-
- ret = wl12xx_cmd_configure(wl, &pta, sizeof(pta));
- if (ret < 0) {
- wl12xx_warning("failed to set softgemini enable: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_sg_cfg(struct wl12xx *wl)
-{
- struct acx_bt_wlan_coex_param param;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx sg cfg");
-
- /* BT-WLAN coext parameters */
- param.header.id = ACX_SG_CFG;
- param.header.len = sizeof(param) - sizeof(struct acx_header);
-
- param.min_rate = RATE_INDEX_24MBPS;
- param.bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
- param.wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
- param.sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
- param.rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
- param.tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
- param.rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
- param.tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
- param.wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
- param.bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
- param.next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
- param.wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
- param.hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
- param.next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
- param.antenna_type = PTA_ANTENNA_TYPE_DEF;
- param.signal_type = PTA_SIGNALING_TYPE_DEF;
- param.afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
- param.quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
- param.max_cts = PTA_MAX_NUM_CTS_DEF;
- param.wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
- param.bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
- param.missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
- param.wlan_elp_hp = PTA_ELP_HP_DEF;
- param.bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
- param.ack_mode_dual_ant = PTA_ACK_MODE_DEF;
- param.pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
- param.pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
- param.bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
-
- ret = wl12xx_cmd_configure(wl, &param, sizeof(param));
- if (ret < 0) {
- wl12xx_warning("failed to set sg config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_cca_threshold(struct wl12xx *wl)
-{
- struct acx_energy_detection detection;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx cca threshold");
-
- detection.header.id = ACX_CCA_THRESHOLD;
- detection.header.len = sizeof(detection) - sizeof(struct acx_header);
-
- detection.rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
- detection.tx_energy_detection = 0;
-
- ret = wl12xx_cmd_configure(wl, &detection, sizeof(detection));
- if (ret < 0) {
- wl12xx_warning("failed to set cca threshold: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl)
-{
- struct acx_beacon_broadcast bb;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx bcn dtim options");
-
- bb.header.id = ACX_BCN_DTIM_OPTIONS;
- bb.header.len = sizeof(bb) - sizeof(struct acx_header);
-
- bb.beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
- bb.broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
- bb.rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
- bb.ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
-
- ret = wl12xx_cmd_configure(wl, &bb, sizeof(bb));
- if (ret < 0) {
- wl12xx_warning("failed to set rx config: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid)
-{
- struct acx_aid acx_aid;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx aid");
-
- acx_aid.header.id = ACX_AID;
- acx_aid.header.len = sizeof(acx_aid) - sizeof(struct acx_header);
-
- acx_aid.aid = aid;
-
- ret = wl12xx_cmd_configure(wl, &acx_aid, sizeof(acx_aid));
- if (ret < 0) {
- wl12xx_warning("failed to set aid: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask)
-{
- struct acx_event_mask mask;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx event mbox mask");
-
- mask.header.id = ACX_EVENT_MBOX_MASK;
- mask.header.len = sizeof(mask) - sizeof(struct acx_header);
-
- /* high event mask is unused */
- mask.high_event_mask = 0xffffffff;
-
- mask.event_mask = event_mask;
-
- ret = wl12xx_cmd_configure(wl, &mask, sizeof(mask));
- if (ret < 0) {
- wl12xx_warning("failed to set aid: %d", ret);
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble)
-{
- struct acx_preamble ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx_set_preamble");
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = ACX_PREAMBLE_TYPE;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.preamble = preamble;
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("Setting of preamble failed: %d", ret);
- return ret;
- }
- return 0;
-}
-
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
- enum acx_ctsprotect_type ctsprotect)
-{
- struct acx_ctsprotect ie;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx_set_ctsprotect");
-
- memset(&ie, 0, sizeof(ie));
-
- ie.header.id = ACX_CTS_PROTECTION;
- ie.header.len = sizeof(ie) - sizeof(struct acx_header);
- ie.ctsprotect = ctsprotect;
- ret = wl12xx_cmd_configure(wl, &ie, sizeof(ie));
- if (ret < 0) {
- wl12xx_warning("Setting of ctsprotect failed: %d", ret);
- return ret;
- }
- return 0;
-}
-
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats)
-{
- struct wl12xx_command *answer;
- int ret;
-
- wl12xx_debug(DEBUG_ACX, "acx statistics");
-
- answer = kmalloc(sizeof(*answer), GFP_KERNEL);
- if (!answer) {
- wl12xx_warning("could not allocate memory for acx statistics");
- ret = -ENOMEM;
- goto out;
- }
-
- ret = wl12xx_cmd_interrogate(wl, ACX_STATISTICS, sizeof(*answer),
- answer);
- if (ret < 0) {
- wl12xx_warning("acx statistics failed: %d", ret);
- goto out;
- }
-
- memcpy(stats, answer->parameters, sizeof(*stats));
-
-out:
- kfree(answer);
- return ret;
-}
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
deleted file mode 100644
index f73ab602b7a..00000000000
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ /dev/null
@@ -1,353 +0,0 @@
-#include "cmd.h"
-
-#include <linux/module.h>
-#include <linux/crc7.h>
-#include <linux/spi/spi.h>
-
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
-#include "reg.h"
-#include "spi.h"
-#include "ps.h"
-
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len)
-{
- struct wl12xx_command cmd;
- unsigned long timeout;
- size_t cmd_len;
- u32 intr;
- int ret = 0;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.id = type;
- cmd.status = 0;
- memcpy(cmd.parameters, buf, buf_len);
- cmd_len = ALIGN(buf_len, 4) + CMDMBOX_HEADER_LEN;
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_spi_mem_write(wl, wl->cmd_box_addr, &cmd, cmd_len);
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
-
- timeout = jiffies + msecs_to_jiffies(WL12XX_COMMAND_TIMEOUT);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- while (!(intr & wl->chip.intr_cmd_complete)) {
- if (time_after(jiffies, timeout)) {
- wl12xx_error("command complete timeout");
- ret = -ETIMEDOUT;
- goto out;
- }
-
- msleep(1);
-
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
- }
-
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
- wl->chip.intr_cmd_complete);
-
-out:
- wl12xx_ps_elp_sleep(wl);
-
- return ret;
-}
-
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer)
-{
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd test");
-
- ret = wl12xx_cmd_send(wl, CMD_TEST, buf, buf_len);
- if (ret < 0) {
- wl12xx_warning("TEST command failed");
- return ret;
- }
-
- if (answer) {
- struct wl12xx_command *cmd_answer;
-
- /*
- * The test command got in, we can read the answer.
- * The answer would be a wl12xx_command, where the
- * parameter array contains the actual answer.
- */
-
- wl12xx_ps_elp_wakeup(wl);
-
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
-
- wl12xx_ps_elp_sleep(wl);
-
- cmd_answer = buf;
- if (cmd_answer->status != CMD_STATUS_SUCCESS)
- wl12xx_error("TEST command answer error: %d",
- cmd_answer->status);
- }
-
- return 0;
-}
-
-
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
- void *answer)
-{
- struct wl12xx_command *cmd;
- struct acx_header header;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd interrogate");
-
- header.id = ie_id;
- header.len = ie_len - sizeof(header);
-
- ret = wl12xx_cmd_send(wl, CMD_INTERROGATE, &header, sizeof(header));
- if (ret < 0) {
- wl12xx_error("INTERROGATE command failed");
- return ret;
- }
-
- wl12xx_ps_elp_wakeup(wl);
-
- /* the interrogate command got in, we can read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, answer,
- CMDMBOX_HEADER_LEN + ie_len);
-
- wl12xx_ps_elp_sleep(wl);
-
- cmd = answer;
- if (cmd->status != CMD_STATUS_SUCCESS)
- wl12xx_error("INTERROGATE command error: %d",
- cmd->status);
-
- return 0;
-
-}
-
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len)
-{
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd configure");
-
- ret = wl12xx_cmd_send(wl, CMD_CONFIGURE, ie,
- ie_len);
- if (ret < 0) {
- wl12xx_warning("CONFIGURE command NOK");
- return ret;
- }
-
- return 0;
-
-}
-
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
- void *bitmap, u16 bitmap_len, u8 bitmap_control)
-{
- struct vbm_update_request vbm;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd vbm");
-
- /* Count and period will be filled by the target */
- vbm.tim.bitmap_ctrl = bitmap_control;
- if (bitmap_len > PARTIAL_VBM_MAX) {
- wl12xx_warning("cmd vbm len is %d B, truncating to %d",
- bitmap_len, PARTIAL_VBM_MAX);
- bitmap_len = PARTIAL_VBM_MAX;
- }
- memcpy(vbm.tim.pvb_field, bitmap, bitmap_len);
- vbm.tim.identity = identity;
- vbm.tim.length = bitmap_len + 3;
-
- vbm.len = cpu_to_le16(bitmap_len + 5);
-
- ret = wl12xx_cmd_send(wl, CMD_VBM, &vbm, sizeof(vbm));
- if (ret < 0) {
- wl12xx_error("VBM command failed");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable)
-{
- int ret;
- u16 cmd_rx, cmd_tx;
-
- wl12xx_debug(DEBUG_CMD, "cmd data path");
-
- if (enable) {
- cmd_rx = CMD_ENABLE_RX;
- cmd_tx = CMD_ENABLE_TX;
- } else {
- cmd_rx = CMD_DISABLE_RX;
- cmd_tx = CMD_DISABLE_TX;
- }
-
- ret = wl12xx_cmd_send(wl, cmd_rx, &channel, sizeof(channel));
- if (ret < 0) {
- wl12xx_error("rx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
- return ret;
- }
-
- wl12xx_debug(DEBUG_BOOT, "rx %s cmd channel %d",
- enable ? "start" : "stop", channel);
-
- ret = wl12xx_cmd_send(wl, cmd_tx, &channel, sizeof(channel));
- if (ret < 0) {
- wl12xx_error("tx %s cmd for channel %d failed",
- enable ? "start" : "stop", channel);
- return ret;
- }
-
- wl12xx_debug(DEBUG_BOOT, "tx %s cmd channel %d",
- enable ? "start" : "stop", channel);
-
- return 0;
-}
-
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
- u16 beacon_interval, u8 wait)
-{
- unsigned long timeout;
- struct cmd_join join = {};
- int ret, i;
- u8 *bssid;
-
- /* FIXME: this should be in main.c */
- ret = wl12xx_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
- DEFAULT_HW_GEN_MODULATION_TYPE,
- wl->tx_mgmt_frm_rate,
- wl->tx_mgmt_frm_mod);
- if (ret < 0)
- return ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd join");
-
- /* Reverse order BSSID */
- bssid = (u8 *)&join.bssid_lsb;
- for (i = 0; i < ETH_ALEN; i++)
- bssid[i] = wl->bssid[ETH_ALEN - i - 1];
-
- join.rx_config_options = wl->rx_config;
- join.rx_filter_options = wl->rx_filter;
-
- join.basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
- RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
-
- join.beacon_interval = beacon_interval;
- join.dtim_interval = dtim_interval;
- join.bss_type = bss_type;
- join.channel = wl->channel;
- join.ctrl = JOIN_CMD_CTRL_TX_FLUSH;
-
- ret = wl12xx_cmd_send(wl, CMD_START_JOIN, &join, sizeof(join));
- if (ret < 0) {
- wl12xx_error("failed to initiate cmd join");
- return ret;
- }
-
- timeout = msecs_to_jiffies(JOIN_TIMEOUT);
-
- /*
- * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
- * simplify locking we just sleep instead, for now
- */
- if (wait)
- msleep(10);
-
- return 0;
-}
-
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode)
-{
- int ret;
- struct acx_ps_params ps_params;
-
- /* FIXME: this should be in ps.c */
- ret = wl12xx_acx_wake_up_conditions(wl, wl->listen_int);
- if (ret < 0) {
- wl12xx_error("Couldnt set wake up conditions");
- return ret;
- }
-
- wl12xx_debug(DEBUG_CMD, "cmd set ps mode");
-
- ps_params.ps_mode = ps_mode;
- ps_params.send_null_data = 1;
- ps_params.retries = 5;
- ps_params.hang_over_period = 128;
- ps_params.null_data_rate = 1; /* 1 Mbps */
-
- ret = wl12xx_cmd_send(wl, CMD_SET_PS_MODE, &ps_params,
- sizeof(ps_params));
- if (ret < 0) {
- wl12xx_error("cmd set_ps_mode failed");
- return ret;
- }
-
- return 0;
-}
-
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer)
-{
- struct cmd_read_write_memory mem_cmd, *mem_answer;
- struct wl12xx_command cmd;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd read memory");
-
- memset(&mem_cmd, 0, sizeof(mem_cmd));
- mem_cmd.addr = addr;
- mem_cmd.size = len;
-
- ret = wl12xx_cmd_send(wl, CMD_READ_MEMORY, &mem_cmd, sizeof(mem_cmd));
- if (ret < 0) {
- wl12xx_error("read memory command failed: %d", ret);
- return ret;
- }
-
- /* the read command got in, we can now read the answer */
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, &cmd,
- CMDMBOX_HEADER_LEN + sizeof(mem_cmd));
-
- if (cmd.status != CMD_STATUS_SUCCESS)
- wl12xx_error("error in read command result: %d", cmd.status);
-
- mem_answer = (struct cmd_read_write_memory *) cmd.parameters;
- memcpy(answer, mem_answer->value, len);
-
- return 0;
-}
-
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
- void *buf, size_t buf_len)
-{
- struct wl12xx_cmd_packet_template template;
- int ret;
-
- wl12xx_debug(DEBUG_CMD, "cmd template %d", cmd_id);
-
- memset(&template, 0, sizeof(template));
-
- WARN_ON(buf_len > WL12XX_MAX_TEMPLATE_SIZE);
- buf_len = min_t(size_t, buf_len, WL12XX_MAX_TEMPLATE_SIZE);
- template.size = cpu_to_le16(buf_len);
-
- if (buf)
- memcpy(template.template, buf, buf_len);
-
- ret = wl12xx_cmd_send(wl, cmd_id, &template,
- sizeof(template.size) + buf_len);
- if (ret < 0) {
- wl12xx_warning("cmd set_template failed: %d", ret);
- return ret;
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index e421643215c..2de47cc32b8 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -26,7 +26,6 @@
#define __REG_H__
#include <linux/bitops.h>
-#include "wl12xx.h"
#define REGISTERS_BASE 0x00300000
#define DRPW_BASE 0x00310000
diff --git a/drivers/net/wireless/wl12xx/wl1251.h b/drivers/net/wireless/wl12xx/wl1251.h
index 1f4a4433039..665aca02bea 100644
--- a/drivers/net/wireless/wl12xx/wl1251.h
+++ b/drivers/net/wireless/wl12xx/wl1251.h
@@ -1,7 +1,8 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
- * Copyright (C) 2008 Nokia Corporation
+ * Copyright (c) 1998-2007 Texas Instruments Incorporated
+ * Copyright (C) 2008-2009 Nokia Corporation
*
* Contact: Kalle Valo <kalle.valo@nokia.com>
*
@@ -24,142 +25,396 @@
#ifndef __WL1251_H__
#define __WL1251_H__
+#include <linux/mutex.h>
+#include <linux/list.h>
#include <linux/bitops.h>
-
-#include "wl12xx.h"
-#include "acx.h"
-
-#define WL1251_FW_NAME "wl1251-fw.bin"
-#define WL1251_NVS_NAME "wl1251-nvs.bin"
-
-#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
-
-void wl1251_setup(struct wl12xx *wl);
-
-
-struct wl1251_acx_memory {
- __le16 num_stations; /* number of STAs to be supported. */
- u16 reserved_1;
+#include <net/mac80211.h>
+
+#define DRIVER_NAME "wl1251"
+#define DRIVER_PREFIX DRIVER_NAME ": "
+
+enum {
+ DEBUG_NONE = 0,
+ DEBUG_IRQ = BIT(0),
+ DEBUG_SPI = BIT(1),
+ DEBUG_BOOT = BIT(2),
+ DEBUG_MAILBOX = BIT(3),
+ DEBUG_NETLINK = BIT(4),
+ DEBUG_EVENT = BIT(5),
+ DEBUG_TX = BIT(6),
+ DEBUG_RX = BIT(7),
+ DEBUG_SCAN = BIT(8),
+ DEBUG_CRYPT = BIT(9),
+ DEBUG_PSM = BIT(10),
+ DEBUG_MAC80211 = BIT(11),
+ DEBUG_CMD = BIT(12),
+ DEBUG_ACX = BIT(13),
+ DEBUG_ALL = ~0,
+};
+
+#define DEBUG_LEVEL (DEBUG_NONE)
+
+#define DEBUG_DUMP_LIMIT 1024
+
+#define wl1251_error(fmt, arg...) \
+ printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
+
+#define wl1251_warning(fmt, arg...) \
+ printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
+
+#define wl1251_notice(fmt, arg...) \
+ printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_info(fmt, arg...) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
+
+#define wl1251_debug(level, fmt, arg...) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
+ } while (0)
+
+#define wl1251_dump(level, prefix, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ 0); \
+ } while (0)
+
+#define wl1251_dump_ascii(level, prefix, buf, len) \
+ do { \
+ if (level & DEBUG_LEVEL) \
+ print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
+ DUMP_PREFIX_OFFSET, 16, 1, \
+ buf, \
+ min_t(size_t, len, DEBUG_DUMP_LIMIT), \
+ true); \
+ } while (0)
+
+#define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
+ CFG_BSSID_FILTER_EN)
+
+#define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \
+ CFG_RX_MGMT_EN | \
+ CFG_RX_DATA_EN | \
+ CFG_RX_CTL_EN | \
+ CFG_RX_BCN_EN | \
+ CFG_RX_AUTH_EN | \
+ CFG_RX_ASSOC_EN)
+
+#define WL1251_BUSY_WORD_LEN 8
+
+struct boot_attr {
+ u32 radio_type;
+ u8 mac_clock;
+ u8 arm_clock;
+ int firmware_debug;
+ u32 minor;
+ u32 major;
+ u32 bugfix;
+};
+
+enum wl1251_state {
+ WL1251_STATE_OFF,
+ WL1251_STATE_ON,
+ WL1251_STATE_PLT,
+};
+
+enum wl1251_partition_type {
+ PART_DOWN,
+ PART_WORK,
+ PART_DRPW,
+
+ PART_TABLE_LEN
+};
+
+struct wl1251_partition {
+ u32 size;
+ u32 start;
+};
+
+struct wl1251_partition_set {
+ struct wl1251_partition mem;
+ struct wl1251_partition reg;
+};
+
+struct wl1251;
+
+/* FIXME: I'm not sure about this structure name */
+struct wl1251_chip {
+ u32 id;
+
+ const char *fw_filename;
+ const char *nvs_filename;
+
+ char fw_ver[21];
+
+ unsigned int power_on_sleep;
+ int intr_cmd_complete;
+ int intr_init_complete;
+
+ int (*op_upload_fw)(struct wl1251 *wl);
+ int (*op_upload_nvs)(struct wl1251 *wl);
+ int (*op_boot)(struct wl1251 *wl);
+ void (*op_set_ecpu_ctrl)(struct wl1251 *wl, u32 flag);
+ void (*op_target_enable_interrupts)(struct wl1251 *wl);
+ int (*op_hw_init)(struct wl1251 *wl);
+ int (*op_plt_init)(struct wl1251 *wl);
+ void (*op_tx_flush)(struct wl1251 *wl);
+ void (*op_fw_version)(struct wl1251 *wl);
+ int (*op_cmd_join)(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
+ u16 beacon_interval, u8 wait);
+
+ struct wl1251_partition_set *p_table;
+ enum wl12xx_acx_int_reg *acx_reg_table;
+};
+
+struct wl1251_stats {
+ struct acx_statistics *fw_stats;
+ unsigned long fw_stats_update;
+
+ unsigned int retry_count;
+ unsigned int excessive_retries;
+};
+
+struct wl1251_debugfs {
+ struct dentry *rootdir;
+ struct dentry *fw_statistics;
+
+ struct dentry *tx_internal_desc_overflow;
+
+ struct dentry *rx_out_of_mem;
+ struct dentry *rx_hdr_overflow;
+ struct dentry *rx_hw_stuck;
+ struct dentry *rx_dropped;
+ struct dentry *rx_fcs_err;
+ struct dentry *rx_xfr_hint_trig;
+ struct dentry *rx_path_reset;
+ struct dentry *rx_reset_counter;
+
+ struct dentry *dma_rx_requested;
+ struct dentry *dma_rx_errors;
+ struct dentry *dma_tx_requested;
+ struct dentry *dma_tx_errors;
+
+ struct dentry *isr_cmd_cmplt;
+ struct dentry *isr_fiqs;
+ struct dentry *isr_rx_headers;
+ struct dentry *isr_rx_mem_overflow;
+ struct dentry *isr_rx_rdys;
+ struct dentry *isr_irqs;
+ struct dentry *isr_tx_procs;
+ struct dentry *isr_decrypt_done;
+ struct dentry *isr_dma0_done;
+ struct dentry *isr_dma1_done;
+ struct dentry *isr_tx_exch_complete;
+ struct dentry *isr_commands;
+ struct dentry *isr_rx_procs;
+ struct dentry *isr_hw_pm_mode_changes;
+ struct dentry *isr_host_acknowledges;
+ struct dentry *isr_pci_pm;
+ struct dentry *isr_wakeups;
+ struct dentry *isr_low_rssi;
+
+ struct dentry *wep_addr_key_count;
+ struct dentry *wep_default_key_count;
+ /* skipping wep.reserved */
+ struct dentry *wep_key_not_found;
+ struct dentry *wep_decrypt_fail;
+ struct dentry *wep_packets;
+ struct dentry *wep_interrupt;
+
+ struct dentry *pwr_ps_enter;
+ struct dentry *pwr_elp_enter;
+ struct dentry *pwr_missing_bcns;
+ struct dentry *pwr_wake_on_host;
+ struct dentry *pwr_wake_on_timer_exp;
+ struct dentry *pwr_tx_with_ps;
+ struct dentry *pwr_tx_without_ps;
+ struct dentry *pwr_rcvd_beacons;
+ struct dentry *pwr_power_save_off;
+ struct dentry *pwr_enable_ps;
+ struct dentry *pwr_disable_ps;
+ struct dentry *pwr_fix_tsf_ps;
+ /* skipping cont_miss_bcns_spread for now */
+ struct dentry *pwr_rcvd_awake_beacons;
+
+ struct dentry *mic_rx_pkts;
+ struct dentry *mic_calc_failure;
+
+ struct dentry *aes_encrypt_fail;
+ struct dentry *aes_decrypt_fail;
+ struct dentry *aes_encrypt_packets;
+ struct dentry *aes_decrypt_packets;
+ struct dentry *aes_encrypt_interrupt;
+ struct dentry *aes_decrypt_interrupt;
+
+ struct dentry *event_heart_beat;
+ struct dentry *event_calibration;
+ struct dentry *event_rx_mismatch;
+ struct dentry *event_rx_mem_empty;
+ struct dentry *event_rx_pool;
+ struct dentry *event_oom_late;
+ struct dentry *event_phy_transmit_error;
+ struct dentry *event_tx_stuck;
+
+ struct dentry *ps_pspoll_timeouts;
+ struct dentry *ps_upsd_timeouts;
+ struct dentry *ps_upsd_max_sptime;
+ struct dentry *ps_upsd_max_apturn;
+ struct dentry *ps_pspoll_max_apturn;
+ struct dentry *ps_pspoll_utilization;
+ struct dentry *ps_upsd_utilization;
+
+ struct dentry *rxpipe_rx_prep_beacon_drop;
+ struct dentry *rxpipe_descr_host_int_trig_rx_data;
+ struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
+ struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
+ struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
+
+ struct dentry *tx_queue_len;
+
+ struct dentry *retry_count;
+ struct dentry *excessive_retries;
+};
+
+struct wl1251 {
+ struct ieee80211_hw *hw;
+ bool mac80211_registered;
+
+ struct spi_device *spi;
+
+ void (*set_power)(bool enable);
+ int irq;
+
+ enum wl1251_state state;
+ struct mutex mutex;
+
+ int physical_mem_addr;
+ int physical_reg_addr;
+ int virtual_mem_addr;
+ int virtual_reg_addr;
+
+ struct wl1251_chip chip;
+
+ int cmd_box_addr;
+ int event_box_addr;
+ struct boot_attr boot_attr;
+
+ u8 *fw;
+ size_t fw_len;
+ u8 *nvs;
+ size_t nvs_len;
+
+ u8 bssid[ETH_ALEN];
+ u8 mac_addr[ETH_ALEN];
+ u8 bss_type;
+ u8 listen_int;
+ int channel;
+
+ void *target_mem_map;
+ struct acx_data_path_params_resp *data_path;
+
+ /* Number of TX packets transferred to the FW, modulo 16 */
+ u32 data_in_count;
+
+ /* Frames scheduled for transmission, not handled yet */
+ struct sk_buff_head tx_queue;
+ bool tx_queue_stopped;
+
+ struct work_struct tx_work;
+ struct work_struct filter_work;
+
+ /* Pending TX frames */
+ struct sk_buff *tx_frames[16];
/*
- * Nmber of memory buffers for the RX mem pool.
- * The actual number may be less if there are
- * not enough blocks left for the minimum num
- * of TX ones.
+ * Index pointing to the next TX complete entry
+ * in the cyclic XT complete array we get from
+ * the FW.
*/
- u8 rx_mem_block_num;
- u8 reserved_2;
- u8 num_tx_queues; /* From 1 to 16 */
- u8 host_if_options; /* HOST_IF* */
- u8 tx_min_mem_block_num;
- u8 num_ssid_profiles;
- __le16 debug_buffer_size;
-} __attribute__ ((packed));
-
-
-#define ACX_RX_DESC_MIN 1
-#define ACX_RX_DESC_MAX 127
-#define ACX_RX_DESC_DEF 32
-struct wl1251_acx_rx_queue_config {
- u8 num_descs;
- u8 pad;
- u8 type;
- u8 priority;
- __le32 dma_address;
-} __attribute__ ((packed));
-
-#define ACX_TX_DESC_MIN 1
-#define ACX_TX_DESC_MAX 127
-#define ACX_TX_DESC_DEF 16
-struct wl1251_acx_tx_queue_config {
- u8 num_descs;
- u8 pad[2];
- u8 attributes;
-} __attribute__ ((packed));
-
-#define MAX_TX_QUEUE_CONFIGS 5
-#define MAX_TX_QUEUES 4
-struct wl1251_acx_config_memory {
- struct acx_header header;
-
- struct wl1251_acx_memory mem_config;
- struct wl1251_acx_rx_queue_config rx_queue_config;
- struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
-} __attribute__ ((packed));
-
-struct wl1251_acx_mem_map {
- struct acx_header header;
-
- void *code_start;
- void *code_end;
-
- void *wep_defkey_start;
- void *wep_defkey_end;
+ u32 next_tx_complete;
- void *sta_table_start;
- void *sta_table_end;
+ /* FW Rx counter */
+ u32 rx_counter;
- void *packet_template_start;
- void *packet_template_end;
+ /* Rx frames handled */
+ u32 rx_handled;
- void *queue_memory_start;
- void *queue_memory_end;
+ /* Current double buffer */
+ u32 rx_current_buffer;
+ u32 rx_last_id;
- void *packet_memory_pool_start;
- void *packet_memory_pool_end;
+ /* The target interrupt mask */
+ u32 intr_mask;
+ struct work_struct irq_work;
- void *debug_buffer1_start;
- void *debug_buffer1_end;
+ /* The mbox event mask */
+ u32 event_mask;
- void *debug_buffer2_start;
- void *debug_buffer2_end;
+ /* Mailbox pointers */
+ u32 mbox_ptr[2];
- /* Number of blocks FW allocated for TX packets */
- u32 num_tx_mem_blocks;
+ /* Are we currently scanning */
+ bool scanning;
- /* Number of blocks FW allocated for RX packets */
- u32 num_rx_mem_blocks;
-} __attribute__ ((packed));
+ /* Our association ID */
+ u16 aid;
-/*************************************************************************
+ /* Default key (for WEP) */
+ u32 default_key;
- Host Interrupt Register (WiLink -> Host)
+ unsigned int tx_mgmt_frm_rate;
+ unsigned int tx_mgmt_frm_mod;
-**************************************************************************/
+ unsigned int rx_config;
+ unsigned int rx_filter;
-/* RX packet is ready in Xfer buffer #0 */
-#define WL1251_ACX_INTR_RX0_DATA BIT(0)
+ /* is firmware in elp mode */
+ bool elp;
-/* TX result(s) are in the TX complete buffer */
-#define WL1251_ACX_INTR_TX_RESULT BIT(1)
+ /* we can be in psm, but not in elp, we have to differentiate */
+ bool psm;
-/* OBSOLETE */
-#define WL1251_ACX_INTR_TX_XFR BIT(2)
+ /* PSM mode requested */
+ bool psm_requested;
-/* RX packet is ready in Xfer buffer #1 */
-#define WL1251_ACX_INTR_RX1_DATA BIT(3)
+ /* in dBm */
+ int power_level;
-/* Event was entered to Event MBOX #A */
-#define WL1251_ACX_INTR_EVENT_A BIT(4)
+ struct wl1251_stats stats;
+ struct wl1251_debugfs debugfs;
-/* Event was entered to Event MBOX #B */
-#define WL1251_ACX_INTR_EVENT_B BIT(5)
+ u32 buffer_32;
+ u32 buffer_cmd;
+ u8 buffer_busyword[WL1251_BUSY_WORD_LEN];
+ struct wl1251_rx_descriptor *rx_descriptor;
+};
-/* OBSOLETE */
-#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
+int wl1251_plt_start(struct wl1251 *wl);
+int wl1251_plt_stop(struct wl1251 *wl);
-/* Trace meassge on MBOX #A */
-#define WL1251_ACX_INTR_TRACE_A BIT(7)
+#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
+#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
+#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-/* Trace meassge on MBOX #B */
-#define WL1251_ACX_INTR_TRACE_B BIT(8)
+#define WL1251_DEFAULT_POWER_LEVEL 20
-/* Command processing completion */
-#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
+#define WL1251_TX_QUEUE_MAX_LENGTH 20
-/* Init sequence is done */
-#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
+/* Different chips need different sleep times after power on. WL1271 needs
+ * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we
+ * know the chip ID, we change the sleep value in the wl1251 chip structure,
+ * so in subsequent power ons, we don't waste more time then needed. */
+#define WL1251_DEFAULT_POWER_ON_SLEEP 200
-#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
+#define CHIP_ID_1251_PG10 (0x7010101)
+#define CHIP_ID_1251_PG11 (0x7020101)
+#define CHIP_ID_1251_PG12 (0x7030101)
+#define CHIP_ID_1271_PG10 (0x4030101)
+#define CHIP_ID_1271_PG20 (0x4030111)
#endif
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.c b/drivers/net/wireless/wl12xx/wl1251_acx.c
new file mode 100644
index 00000000000..a46c92a2952
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.c
@@ -0,0 +1,840 @@
+#include "wl1251_acx.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1251.h"
+#include "reg.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
+ u8 mgt_rate, u8 mgt_mod)
+{
+ struct acx_fw_gen_frame_rates *rates;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx frame rates");
+
+ rates = kzalloc(sizeof(*rates), GFP_KERNEL);
+ if (!rates) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rates->tx_ctrl_frame_rate = ctrl_rate;
+ rates->tx_ctrl_frame_mod = ctrl_mod;
+ rates->tx_mgt_frame_rate = mgt_rate;
+ rates->tx_mgt_frame_mod = mgt_mod;
+
+ ret = wl1251_cmd_configure(wl, ACX_FW_GEN_FRAME_RATES,
+ rates, sizeof(*rates));
+ if (ret < 0) {
+ wl1251_error("Failed to set FW rates and modulation");
+ goto out;
+ }
+
+out:
+ kfree(rates);
+ return ret;
+}
+
+
+int wl1251_acx_station_id(struct wl1251 *wl)
+{
+ struct acx_dot11_station_id *mac;
+ int ret, i;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_station_id");
+
+ mac = kzalloc(sizeof(*mac), GFP_KERNEL);
+ if (!mac) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ mac->mac[i] = wl->mac_addr[ETH_ALEN - 1 - i];
+
+ ret = wl1251_cmd_configure(wl, DOT11_STATION_ID, mac, sizeof(*mac));
+ if (ret < 0)
+ goto out;
+
+out:
+ kfree(mac);
+ return ret;
+}
+
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id)
+{
+ struct acx_dot11_default_key *default_key;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_default_key (%d)", key_id);
+
+ default_key = kzalloc(sizeof(*default_key), GFP_KERNEL);
+ if (!default_key) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ default_key->id = key_id;
+
+ ret = wl1251_cmd_configure(wl, DOT11_DEFAULT_KEY,
+ default_key, sizeof(*default_key));
+ if (ret < 0) {
+ wl1251_error("Couldn't set default key");
+ goto out;
+ }
+
+ wl->default_key = key_id;
+
+out:
+ kfree(default_key);
+ return ret;
+}
+
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+ u8 listen_interval)
+{
+ struct acx_wake_up_condition *wake_up;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx wake up conditions");
+
+ wake_up = kzalloc(sizeof(*wake_up), GFP_KERNEL);
+ if (!wake_up) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wake_up->wake_up_event = wake_up_event;
+ wake_up->listen_interval = listen_interval;
+
+ ret = wl1251_cmd_configure(wl, ACX_WAKE_UP_CONDITIONS,
+ wake_up, sizeof(*wake_up));
+ if (ret < 0) {
+ wl1251_warning("could not set wake up conditions: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(wake_up);
+ return ret;
+}
+
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth)
+{
+ struct acx_sleep_auth *auth;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sleep auth");
+
+ auth = kzalloc(sizeof(*auth), GFP_KERNEL);
+ if (!auth) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ auth->sleep_auth = sleep_auth;
+
+ ret = wl1251_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
+ if (ret < 0)
+ return ret;
+
+out:
+ kfree(auth);
+ return ret;
+}
+
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len)
+{
+ struct acx_revision *rev;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx fw rev");
+
+ rev = kzalloc(sizeof(*rev), GFP_KERNEL);
+ if (!rev) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1251_cmd_interrogate(wl, ACX_FW_REV, rev, sizeof(*rev));
+ if (ret < 0) {
+ wl1251_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ /* be careful with the buffer sizes */
+ strncpy(buf, rev->fw_version, min(len, sizeof(rev->fw_version)));
+
+ /*
+ * if the firmware version string is exactly
+ * sizeof(rev->fw_version) long or fw_len is less than
+ * sizeof(rev->fw_version) it won't be null terminated
+ */
+ buf[min(len, sizeof(rev->fw_version)) - 1] = '\0';
+
+out:
+ kfree(rev);
+ return ret;
+}
+
+int wl1251_acx_tx_power(struct wl1251 *wl, int power)
+{
+ struct acx_current_tx_power *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx dot11_cur_tx_pwr");
+
+ if (power < 0 || power > 25)
+ return -EINVAL;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->current_tx_power = power * 10;
+
+ ret = wl1251_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("configure of tx power failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_feature_cfg(struct wl1251 *wl)
+{
+ struct acx_feature_config *feature;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx feature cfg");
+
+ feature = kzalloc(sizeof(*feature), GFP_KERNEL);
+ if (!feature) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
+ feature->data_flow_options = 0;
+ feature->options = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
+ feature, sizeof(*feature));
+ if (ret < 0) {
+ wl1251_error("Couldn't set HW encryption");
+ goto out;
+ }
+
+out:
+ kfree(feature);
+ return ret;
+}
+
+int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map,
+ size_t len)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx mem map");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_MEM_MAP, mem_map, len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int wl1251_acx_data_path_params(struct wl1251 *wl,
+ struct acx_data_path_params_resp *resp)
+{
+ struct acx_data_path_params *params;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx data path params");
+
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ params->rx_packet_ring_chunk_size = DP_RX_PACKET_RING_CHUNK_SIZE;
+ params->tx_packet_ring_chunk_size = DP_TX_PACKET_RING_CHUNK_SIZE;
+
+ params->rx_packet_ring_chunk_num = DP_RX_PACKET_RING_CHUNK_NUM;
+ params->tx_packet_ring_chunk_num = DP_TX_PACKET_RING_CHUNK_NUM;
+
+ params->tx_complete_threshold = 1;
+
+ params->tx_complete_ring_depth = FW_TX_CMPLT_BLOCK_SIZE;
+
+ params->tx_complete_timeout = DP_TX_COMPLETE_TIME_OUT;
+
+ ret = wl1251_cmd_configure(wl, ACX_DATA_PATH_PARAMS,
+ params, sizeof(*params));
+ if (ret < 0)
+ goto out;
+
+ /* FIXME: shouldn't this be ACX_DATA_PATH_RESP_PARAMS? */
+ ret = wl1251_cmd_interrogate(wl, ACX_DATA_PATH_PARAMS,
+ resp, sizeof(*resp));
+
+ if (ret < 0) {
+ wl1251_warning("failed to read data path parameters: %d", ret);
+ goto out;
+ } else if (resp->header.cmd.status != CMD_STATUS_SUCCESS) {
+ wl1251_warning("data path parameter acx status failed");
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ kfree(params);
+ return ret;
+}
+
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time)
+{
+ struct acx_rx_msdu_lifetime *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rx msdu life time");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->lifetime = life_time;
+ ret = wl1251_cmd_configure(wl, DOT11_RX_MSDU_LIFE_TIME,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx msdu life time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter)
+{
+ struct acx_rx_config *rx_config;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rx config");
+
+ rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL);
+ if (!rx_config) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rx_config->config_options = config;
+ rx_config->filter_options = filter;
+
+ ret = wl1251_cmd_configure(wl, ACX_RX_CFG,
+ rx_config, sizeof(*rx_config));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_config);
+ return ret;
+}
+
+int wl1251_acx_pd_threshold(struct wl1251 *wl)
+{
+ struct acx_packet_detection *pd;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx data pd threshold");
+
+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: threshold value not set */
+
+ ret = wl1251_cmd_configure(wl, ACX_PD_THRESHOLD, pd, sizeof(*pd));
+ if (ret < 0) {
+ wl1251_warning("failed to set pd threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pd);
+ return 0;
+}
+
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time)
+{
+ struct acx_slot *slot;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx slot");
+
+ slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ if (!slot) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ slot->wone_index = STATION_WONE_INDEX;
+ slot->slot_time = slot_time;
+
+ ret = wl1251_cmd_configure(wl, ACX_SLOT, slot, sizeof(*slot));
+ if (ret < 0) {
+ wl1251_warning("failed to set slot time: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(slot);
+ return ret;
+}
+
+int wl1251_acx_group_address_tbl(struct wl1251 *wl)
+{
+ struct acx_dot11_grp_addr_tbl *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx group address tbl");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* MAC filtering */
+ acx->enabled = 0;
+ acx->num_groups = 0;
+ memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+
+ ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("failed to set group addr table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_service_period_timeout(struct wl1251 *wl)
+{
+ struct acx_rx_timeout *rx_timeout;
+ int ret;
+
+ rx_timeout = kzalloc(sizeof(*rx_timeout), GFP_KERNEL);
+ if (!rx_timeout) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_ACX, "acx service period timeout");
+
+ rx_timeout->ps_poll_timeout = RX_TIMEOUT_PS_POLL_DEF;
+ rx_timeout->upsd_timeout = RX_TIMEOUT_UPSD_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_SERVICE_PERIOD_TIMEOUT,
+ rx_timeout, sizeof(*rx_timeout));
+ if (ret < 0) {
+ wl1251_warning("failed to set service period timeout: %d",
+ ret);
+ goto out;
+ }
+
+out:
+ kfree(rx_timeout);
+ return ret;
+}
+
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold)
+{
+ struct acx_rts_threshold *rts;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx rts threshold");
+
+ rts = kzalloc(sizeof(*rts), GFP_KERNEL);
+ if (!rts) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ rts->threshold = rts_threshold;
+
+ ret = wl1251_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
+ if (ret < 0) {
+ wl1251_warning("failed to set rts threshold: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(rts);
+ return ret;
+}
+
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl)
+{
+ struct acx_beacon_filter_option *beacon_filter;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx beacon filter opt");
+
+ beacon_filter = kzalloc(sizeof(*beacon_filter), GFP_KERNEL);
+ if (!beacon_filter) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ beacon_filter->enable = 0;
+ beacon_filter->max_num_beacons = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_OPT,
+ beacon_filter, sizeof(*beacon_filter));
+ if (ret < 0) {
+ wl1251_warning("failed to set beacon filter opt: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(beacon_filter);
+ return ret;
+}
+
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl)
+{
+ struct acx_beacon_filter_ie_table *ie_table;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx beacon filter table");
+
+ ie_table = kzalloc(sizeof(*ie_table), GFP_KERNEL);
+ if (!ie_table) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ie_table->num_ie = 0;
+ memset(ie_table->table, 0, BEACON_FILTER_TABLE_MAX_SIZE);
+
+ ret = wl1251_cmd_configure(wl, ACX_BEACON_FILTER_TABLE,
+ ie_table, sizeof(*ie_table));
+ if (ret < 0) {
+ wl1251_warning("failed to set beacon filter table: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(ie_table);
+ return ret;
+}
+
+int wl1251_acx_sg_enable(struct wl1251 *wl)
+{
+ struct acx_bt_wlan_coex *pta;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sg enable");
+
+ pta = kzalloc(sizeof(*pta), GFP_KERNEL);
+ if (!pta) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ pta->enable = SG_ENABLE;
+
+ ret = wl1251_cmd_configure(wl, ACX_SG_ENABLE, pta, sizeof(*pta));
+ if (ret < 0) {
+ wl1251_warning("failed to set softgemini enable: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(pta);
+ return ret;
+}
+
+int wl1251_acx_sg_cfg(struct wl1251 *wl)
+{
+ struct acx_bt_wlan_coex_param *param;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx sg cfg");
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* BT-WLAN coext parameters */
+ param->min_rate = RATE_INDEX_24MBPS;
+ param->bt_hp_max_time = PTA_BT_HP_MAXTIME_DEF;
+ param->wlan_hp_max_time = PTA_WLAN_HP_MAX_TIME_DEF;
+ param->sense_disable_timer = PTA_SENSE_DISABLE_TIMER_DEF;
+ param->rx_time_bt_hp = PTA_PROTECTIVE_RX_TIME_DEF;
+ param->tx_time_bt_hp = PTA_PROTECTIVE_TX_TIME_DEF;
+ param->rx_time_bt_hp_fast = PTA_PROTECTIVE_RX_TIME_FAST_DEF;
+ param->tx_time_bt_hp_fast = PTA_PROTECTIVE_TX_TIME_FAST_DEF;
+ param->wlan_cycle_fast = PTA_CYCLE_TIME_FAST_DEF;
+ param->bt_anti_starvation_period = PTA_ANTI_STARVE_PERIOD_DEF;
+ param->next_bt_lp_packet = PTA_TIMEOUT_NEXT_BT_LP_PACKET_DEF;
+ param->wake_up_beacon = PTA_TIME_BEFORE_BEACON_DEF;
+ param->hp_dm_max_guard_time = PTA_HPDM_MAX_TIME_DEF;
+ param->next_wlan_packet = PTA_TIME_OUT_NEXT_WLAN_DEF;
+ param->antenna_type = PTA_ANTENNA_TYPE_DEF;
+ param->signal_type = PTA_SIGNALING_TYPE_DEF;
+ param->afh_leverage_on = PTA_AFH_LEVERAGE_ON_DEF;
+ param->quiet_cycle_num = PTA_NUMBER_QUIET_CYCLE_DEF;
+ param->max_cts = PTA_MAX_NUM_CTS_DEF;
+ param->wlan_packets_num = PTA_NUMBER_OF_WLAN_PACKETS_DEF;
+ param->bt_packets_num = PTA_NUMBER_OF_BT_PACKETS_DEF;
+ param->missed_rx_avalanche = PTA_RX_FOR_AVALANCHE_DEF;
+ param->wlan_elp_hp = PTA_ELP_HP_DEF;
+ param->bt_anti_starvation_cycles = PTA_ANTI_STARVE_NUM_CYCLE_DEF;
+ param->ack_mode_dual_ant = PTA_ACK_MODE_DEF;
+ param->pa_sd_enable = PTA_ALLOW_PA_SD_DEF;
+ param->pta_auto_mode_enable = PTA_AUTO_MODE_NO_CTS_DEF;
+ param->bt_hp_respected_num = PTA_BT_HP_RESPECTED_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+ if (ret < 0) {
+ wl1251_warning("failed to set sg config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(param);
+ return ret;
+}
+
+int wl1251_acx_cca_threshold(struct wl1251 *wl)
+{
+ struct acx_energy_detection *detection;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx cca threshold");
+
+ detection = kzalloc(sizeof(*detection), GFP_KERNEL);
+ if (!detection) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ detection->rx_cca_threshold = CCA_THRSH_DISABLE_ENERGY_D;
+ detection->tx_energy_detection = 0;
+
+ ret = wl1251_cmd_configure(wl, ACX_CCA_THRESHOLD,
+ detection, sizeof(*detection));
+ if (ret < 0) {
+ wl1251_warning("failed to set cca threshold: %d", ret);
+ return ret;
+ }
+
+out:
+ kfree(detection);
+ return ret;
+}
+
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl)
+{
+ struct acx_beacon_broadcast *bb;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx bcn dtim options");
+
+ bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+ if (!bb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ bb->beacon_rx_timeout = BCN_RX_TIMEOUT_DEF_VALUE;
+ bb->broadcast_timeout = BROADCAST_RX_TIMEOUT_DEF_VALUE;
+ bb->rx_broadcast_in_ps = RX_BROADCAST_IN_PS_DEF_VALUE;
+ bb->ps_poll_threshold = CONSECUTIVE_PS_POLL_FAILURE_DEF;
+
+ ret = wl1251_cmd_configure(wl, ACX_BCN_DTIM_OPTIONS, bb, sizeof(*bb));
+ if (ret < 0) {
+ wl1251_warning("failed to set rx config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(bb);
+ return ret;
+}
+
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid)
+{
+ struct acx_aid *acx_aid;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx aid");
+
+ acx_aid = kzalloc(sizeof(*acx_aid), GFP_KERNEL);
+ if (!acx_aid) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx_aid->aid = aid;
+
+ ret = wl1251_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid));
+ if (ret < 0) {
+ wl1251_warning("failed to set aid: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx_aid);
+ return ret;
+}
+
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask)
+{
+ struct acx_event_mask *mask;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx event mbox mask");
+
+ mask = kzalloc(sizeof(*mask), GFP_KERNEL);
+ if (!mask) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* high event mask is unused */
+ mask->high_event_mask = 0xffffffff;
+
+ mask->event_mask = event_mask;
+
+ ret = wl1251_cmd_configure(wl, ACX_EVENT_MBOX_MASK,
+ mask, sizeof(*mask));
+ if (ret < 0) {
+ wl1251_warning("failed to set acx_event_mbox_mask: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(mask);
+ return ret;
+}
+
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble)
+{
+ struct acx_preamble *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx_set_preamble");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->preamble = preamble;
+
+ ret = wl1251_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of preamble failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_cts_protect(struct wl1251 *wl,
+ enum acx_ctsprotect_type ctsprotect)
+{
+ struct acx_ctsprotect *acx;
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx_set_ctsprotect");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->ctsprotect = ctsprotect;
+
+ ret = wl1251_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_warning("Setting of ctsprotect failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime)
+{
+ struct acx_tsf_info *tsf_info;
+ int ret;
+
+ tsf_info = kzalloc(sizeof(*tsf_info), GFP_KERNEL);
+ if (!tsf_info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = wl1251_cmd_interrogate(wl, ACX_TSF_INFO,
+ tsf_info, sizeof(*tsf_info));
+ if (ret < 0) {
+ wl1251_warning("ACX_FW_REV interrogate failed");
+ goto out;
+ }
+
+ *mactime = tsf_info->current_tsf_lsb |
+ (tsf_info->current_tsf_msb << 31);
+
+out:
+ kfree(tsf_info);
+ return ret;
+}
+
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_ACX, "acx statistics");
+
+ ret = wl1251_cmd_interrogate(wl, ACX_STATISTICS, stats,
+ sizeof(*stats));
+ if (ret < 0) {
+ wl1251_warning("acx statistics failed: %d", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index fb2d2340993..2e7b1933a8f 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,14 +22,20 @@
*
*/
-#ifndef __WL12XX_ACX_H__
-#define __WL12XX_ACX_H__
+#ifndef __WL1251_ACX_H__
+#define __WL1251_ACX_H__
-#include "wl12xx.h"
+#include "wl1251.h"
+#include "wl1251_cmd.h"
/* Target's information element */
struct acx_header {
+ struct wl1251_cmd_header cmd;
+
+ /* acx (or information element) header */
u16 id;
+
+ /* payload length (not including headers */
u16 len;
};
@@ -85,15 +91,15 @@ struct acx_revision {
u32 hw_version;
} __attribute__ ((packed));
-enum wl12xx_psm_mode {
+enum wl1251_psm_mode {
/* Active mode */
- WL12XX_PSM_CAM = 0,
+ WL1251_PSM_CAM = 0,
/* Power save mode */
- WL12XX_PSM_PS = 1,
+ WL1251_PSM_PS = 1,
/* Extreme low power */
- WL12XX_PSM_ELP = 2,
+ WL1251_PSM_ELP = 2,
};
struct acx_sleep_auth {
@@ -107,25 +113,6 @@ struct acx_sleep_auth {
u8 padding[3];
} __attribute__ ((packed));
-#define TIM_ELE_ID 5
-#define PARTIAL_VBM_MAX 251
-
-struct tim {
- u8 identity;
- u8 length;
- u8 dtim_count;
- u8 dtim_period;
- u8 bitmap_ctrl;
- u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
-
-/* Virtual Bit Map update */
-struct vbm_update_request {
- __le16 len;
- u8 padding[2];
- struct tim tim;
-} __attribute__ ((packed));
-
enum {
HOSTIF_PCI_MASTER_HOST_INDIRECT,
HOSTIF_PCI_MASTER_HOST_DIRECT,
@@ -202,7 +189,7 @@ struct acx_data_path_params_resp {
#define RX_MSDU_LIFETIME_MAX 0xFFFFFFFF
#define RX_MSDU_LIFETIME_DEF 512000
-struct rx_msdu_lifetime {
+struct acx_rx_msdu_lifetime {
struct acx_header header;
/*
@@ -368,7 +355,7 @@ struct acx_slot {
#define ADDRESS_GROUP_MAX (8)
#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX)
-struct multicast_grp_addr_start {
+struct acx_dot11_grp_addr_tbl {
struct acx_header header;
u8 enabled;
@@ -730,22 +717,13 @@ struct acx_fw_gen_frame_rates {
} __attribute__ ((packed));
/* STA MAC */
-struct dot11_station_id {
+struct acx_dot11_station_id {
struct acx_header header;
u8 mac[ETH_ALEN];
u8 pad[2];
} __attribute__ ((packed));
-/* HW encryption keys */
-#define NUM_ACCESS_CATEGORIES_COPY 4
-#define MAX_KEY_SIZE 32
-
-/* When set, disable HW encryption */
-#define DF_ENCRYPTION_DISABLE 0x01
-/* When set, disable HW decryption */
-#define DF_SNIFF_MODE_ENABLE 0x80
-
struct acx_feature_config {
struct acx_header header;
@@ -753,67 +731,6 @@ struct acx_feature_config {
u32 data_flow_options;
} __attribute__ ((packed));
-enum acx_key_action {
- KEY_ADD_OR_REPLACE = 1,
- KEY_REMOVE = 2,
- KEY_SET_ID = 3,
- MAX_KEY_ACTION = 0xffff,
-};
-
-enum acx_key_type {
- KEY_WEP_DEFAULT = 0,
- KEY_WEP_ADDR = 1,
- KEY_AES_GROUP = 4,
- KEY_AES_PAIRWISE = 5,
- KEY_WEP_GROUP = 6,
- KEY_TKIP_MIC_GROUP = 10,
- KEY_TKIP_MIC_PAIRWISE = 11,
-};
-
-/*
- *
- * key_type_e key size key format
- * ---------- --------- ----------
- * 0x00 5, 13, 29 Key data
- * 0x01 5, 13, 29 Key data
- * 0x04 16 16 bytes of key data
- * 0x05 16 16 bytes of key data
- * 0x0a 32 16 bytes of TKIP key data
- * 8 bytes of RX MIC key data
- * 8 bytes of TX MIC key data
- * 0x0b 32 16 bytes of TKIP key data
- * 8 bytes of RX MIC key data
- * 8 bytes of TX MIC key data
- *
- */
-
-struct acx_set_key {
- /* Ignored for default WEP key */
- u8 addr[ETH_ALEN];
-
- /* key_action_e */
- u16 key_action;
-
- u16 reserved_1;
-
- /* key size in bytes */
- u8 key_size;
-
- /* key_type_e */
- u8 key_type;
- u8 ssid_profile;
-
- /*
- * TKIP, AES: frame's key id field.
- * For WEP default key: key id;
- */
- u8 id;
- u8 reserved_2[6];
- u8 key[MAX_KEY_SIZE];
- u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
- u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
-
struct acx_current_tx_power {
struct acx_header header;
@@ -839,26 +756,6 @@ struct acx_tsf_info {
u8 pad[3];
} __attribute__ ((packed));
-/* 802.11 PS */
-enum acx_ps_mode {
- STATION_ACTIVE_MODE,
- STATION_POWER_SAVE_MODE
-};
-
-struct acx_ps_params {
- u8 ps_mode; /* STATION_* */
- u8 send_null_data; /* Do we have to send NULL data packet ? */
- u8 retries; /* Number of retires for the initial NULL data packet */
-
- /*
- * TUs during which the target stays awake after switching
- * to power save mode.
- */
- u8 hang_over_period;
- u16 null_data_rate;
- u8 pad[2];
-} __attribute__ ((packed));
-
enum acx_wake_up_event {
WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/
WAKE_UP_EVENT_DTIM_BITMAP = 0x02, /* Wake on every DTIM*/
@@ -892,6 +789,7 @@ enum acx_preamble_type {
struct acx_preamble {
struct acx_header header;
+
/*
* When set, the WiLink transmits the frames with a short preamble and
* when cleared, the WiLink transmits the frames with a long preamble.
@@ -1210,36 +1108,39 @@ enum {
};
-int wl12xx_acx_frame_rates(struct wl12xx *wl, u8 ctrl_rate, u8 ctrl_mod,
+int wl1251_acx_frame_rates(struct wl1251 *wl, u8 ctrl_rate, u8 ctrl_mod,
u8 mgt_rate, u8 mgt_mod);
-int wl12xx_acx_station_id(struct wl12xx *wl);
-int wl12xx_acx_default_key(struct wl12xx *wl, u8 key_id);
-int wl12xx_acx_wake_up_conditions(struct wl12xx *wl, u8 listen_interval);
-int wl12xx_acx_sleep_auth(struct wl12xx *wl, u8 sleep_auth);
-int wl12xx_acx_fw_version(struct wl12xx *wl, char *buf, size_t len);
-int wl12xx_acx_tx_power(struct wl12xx *wl, int power);
-int wl12xx_acx_feature_cfg(struct wl12xx *wl);
-int wl12xx_acx_mem_map(struct wl12xx *wl, void *mem_map, size_t len);
-int wl12xx_acx_data_path_params(struct wl12xx *wl,
+int wl1251_acx_station_id(struct wl1251 *wl);
+int wl1251_acx_default_key(struct wl1251 *wl, u8 key_id);
+int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
+ u8 listen_interval);
+int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth);
+int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len);
+int wl1251_acx_tx_power(struct wl1251 *wl, int power);
+int wl1251_acx_feature_cfg(struct wl1251 *wl);
+int wl1251_acx_mem_map(struct wl1251 *wl,
+ struct acx_header *mem_map, size_t len);
+int wl1251_acx_data_path_params(struct wl1251 *wl,
struct acx_data_path_params_resp *data_path);
-int wl12xx_acx_rx_msdu_life_time(struct wl12xx *wl, u32 life_time);
-int wl12xx_acx_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_acx_pd_threshold(struct wl12xx *wl);
-int wl12xx_acx_slot(struct wl12xx *wl, enum acx_slot_type slot_time);
-int wl12xx_acx_group_address_tbl(struct wl12xx *wl);
-int wl12xx_acx_service_period_timeout(struct wl12xx *wl);
-int wl12xx_acx_rts_threshold(struct wl12xx *wl, u16 rts_threshold);
-int wl12xx_acx_beacon_filter_opt(struct wl12xx *wl);
-int wl12xx_acx_beacon_filter_table(struct wl12xx *wl);
-int wl12xx_acx_sg_enable(struct wl12xx *wl);
-int wl12xx_acx_sg_cfg(struct wl12xx *wl);
-int wl12xx_acx_cca_threshold(struct wl12xx *wl);
-int wl12xx_acx_bcn_dtim_options(struct wl12xx *wl);
-int wl12xx_acx_aid(struct wl12xx *wl, u16 aid);
-int wl12xx_acx_event_mbox_mask(struct wl12xx *wl, u32 event_mask);
-int wl12xx_acx_set_preamble(struct wl12xx *wl, enum acx_preamble_type preamble);
-int wl12xx_acx_cts_protect(struct wl12xx *wl,
+int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time);
+int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_acx_pd_threshold(struct wl1251 *wl);
+int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
+int wl1251_acx_group_address_tbl(struct wl1251 *wl);
+int wl1251_acx_service_period_timeout(struct wl1251 *wl);
+int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
+int wl1251_acx_beacon_filter_opt(struct wl1251 *wl);
+int wl1251_acx_beacon_filter_table(struct wl1251 *wl);
+int wl1251_acx_sg_enable(struct wl1251 *wl);
+int wl1251_acx_sg_cfg(struct wl1251 *wl);
+int wl1251_acx_cca_threshold(struct wl1251 *wl);
+int wl1251_acx_bcn_dtim_options(struct wl1251 *wl);
+int wl1251_acx_aid(struct wl1251 *wl, u16 aid);
+int wl1251_acx_event_mbox_mask(struct wl1251 *wl, u32 event_mask);
+int wl1251_acx_set_preamble(struct wl1251 *wl, enum acx_preamble_type preamble);
+int wl1251_acx_cts_protect(struct wl1251 *wl,
enum acx_ctsprotect_type ctsprotect);
-int wl12xx_acx_statistics(struct wl12xx *wl, struct acx_statistics *stats);
+int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats);
+int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime);
-#endif /* __WL12XX_ACX_H__ */
+#endif /* __WL1251_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/wl1251_boot.c
index 48ac08c429b..d8a155dc2fa 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -24,41 +24,41 @@
#include <linux/gpio.h>
#include "reg.h"
-#include "boot.h"
-#include "spi.h"
-#include "event.h"
+#include "wl1251_boot.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
-static void wl12xx_boot_enable_interrupts(struct wl12xx *wl)
+static void wl1251_boot_enable_interrupts(struct wl1251 *wl)
{
enable_irq(wl->irq);
}
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl)
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl)
{
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
- wl12xx_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+ wl1251_reg_write32(wl, HI_CFG, HI_CFG_DEF_VAL);
}
-int wl12xx_boot_soft_reset(struct wl12xx *wl)
+int wl1251_boot_soft_reset(struct wl1251 *wl)
{
unsigned long timeout;
u32 boot_data;
/* perform soft reset */
- wl12xx_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
+ wl1251_reg_write32(wl, ACX_REG_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT);
/* SOFT_RESET is self clearing */
timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME);
while (1) {
- boot_data = wl12xx_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
- wl12xx_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
+ boot_data = wl1251_reg_read32(wl, ACX_REG_SLV_SOFT_RESET);
+ wl1251_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data);
if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0)
break;
if (time_after(jiffies, timeout)) {
/* 1.2 check pWhalBus->uSelfClearTime if the
* timeout was reached */
- wl12xx_error("soft reset timeout");
+ wl1251_error("soft reset timeout");
return -1;
}
@@ -66,15 +66,15 @@ int wl12xx_boot_soft_reset(struct wl12xx *wl)
}
/* disable Rx/Tx */
- wl12xx_reg_write32(wl, ENABLE, 0x0);
+ wl1251_reg_write32(wl, ENABLE, 0x0);
/* disable auto calibration on start*/
- wl12xx_reg_write32(wl, SPARE_A2, 0xffff);
+ wl1251_reg_write32(wl, SPARE_A2, 0xffff);
return 0;
}
-int wl12xx_boot_init_seq(struct wl12xx *wl)
+int wl1251_boot_init_seq(struct wl1251 *wl)
{
u32 scr_pad6, init_data, tmp, elp_cmd, ref_freq;
@@ -96,23 +96,23 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
};
/* read NVS params */
- scr_pad6 = wl12xx_reg_read32(wl, SCR_PAD6);
- wl12xx_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
+ scr_pad6 = wl1251_reg_read32(wl, SCR_PAD6);
+ wl1251_debug(DEBUG_BOOT, "scr_pad6 0x%x", scr_pad6);
/* read ELP_CMD */
- elp_cmd = wl12xx_reg_read32(wl, ELP_CMD);
- wl12xx_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
+ elp_cmd = wl1251_reg_read32(wl, ELP_CMD);
+ wl1251_debug(DEBUG_BOOT, "elp_cmd 0x%x", elp_cmd);
/* set the BB calibration time to be 300 usec (PLL_CAL_TIME) */
ref_freq = scr_pad6 & 0x000000FF;
- wl12xx_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
+ wl1251_debug(DEBUG_BOOT, "ref_freq 0x%x", ref_freq);
- wl12xx_reg_write32(wl, PLL_CAL_TIME, 0x9);
+ wl1251_reg_write32(wl, PLL_CAL_TIME, 0x9);
/*
* PG 1.2: set the clock buffer time to be 210 usec (CLK_BUF_TIME)
*/
- wl12xx_reg_write32(wl, CLK_BUF_TIME, 0x6);
+ wl1251_reg_write32(wl, CLK_BUF_TIME, 0x6);
/*
* set the clock detect feature to work in the restart wu procedure
@@ -120,18 +120,18 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* (ELP_CFG_MODE[13:12])
*/
tmp = ((scr_pad6 & 0x0000FF00) << 4) | 0x00004000;
- wl12xx_reg_write32(wl, ELP_CFG_MODE, tmp);
+ wl1251_reg_write32(wl, ELP_CFG_MODE, tmp);
/* PG 1.2: enable the BB PLL fix. Enable the PLL_LIMP_CLK_EN_CMD */
elp_cmd |= 0x00000040;
- wl12xx_reg_write32(wl, ELP_CMD, elp_cmd);
+ wl1251_reg_write32(wl, ELP_CMD, elp_cmd);
/* PG 1.2: Set the BB PLL stable time to be 1000usec
* (PLL_STABLE_TIME) */
- wl12xx_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
+ wl1251_reg_write32(wl, CFG_PLL_SYNC_CNT, 0x20);
/* PG 1.2: read clock request time */
- init_data = wl12xx_reg_read32(wl, CLK_REQ_TIME);
+ init_data = wl1251_reg_read32(wl, CLK_REQ_TIME);
/*
* PG 1.2: set the clock request time to be ref_clk_settling_time -
@@ -141,35 +141,35 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
tmp = init_data - 0x21;
else
tmp = 0;
- wl12xx_reg_write32(wl, CLK_REQ_TIME, tmp);
+ wl1251_reg_write32(wl, CLK_REQ_TIME, tmp);
/* set BB PLL configurations in RF AFE */
- wl12xx_reg_write32(wl, 0x003058cc, 0x4B5);
+ wl1251_reg_write32(wl, 0x003058cc, 0x4B5);
/* set RF_AFE_REG_5 */
- wl12xx_reg_write32(wl, 0x003058d4, 0x50);
+ wl1251_reg_write32(wl, 0x003058d4, 0x50);
/* set RF_AFE_CTRL_REG_2 */
- wl12xx_reg_write32(wl, 0x00305948, 0x11c001);
+ wl1251_reg_write32(wl, 0x00305948, 0x11c001);
/*
* change RF PLL and BB PLL divider for VCO clock and adjust VCO
* bais current(RF_AFE_REG_13)
*/
- wl12xx_reg_write32(wl, 0x003058f4, 0x1e);
+ wl1251_reg_write32(wl, 0x003058f4, 0x1e);
/* set BB PLL configurations */
tmp = LUT[ref_freq][LUT_PARAM_INTEGER_DIVIDER] | 0x00017000;
- wl12xx_reg_write32(wl, 0x00305840, tmp);
+ wl1251_reg_write32(wl, 0x00305840, tmp);
/* set fractional divider according to Appendix C-BB PLL
* Calculations
*/
tmp = LUT[ref_freq][LUT_PARAM_FRACTIONAL_DIVIDER];
- wl12xx_reg_write32(wl, 0x00305844, tmp);
+ wl1251_reg_write32(wl, 0x00305844, tmp);
/* set the initial data for the sigma delta */
- wl12xx_reg_write32(wl, 0x00305848, 0x3039);
+ wl1251_reg_write32(wl, 0x00305848, 0x3039);
/*
* set the accumulator attenuation value, calibration loop1
@@ -178,14 +178,14 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
*/
tmp = (LUT[ref_freq][LUT_PARAM_ATTN_BB] << 16) |
(LUT[ref_freq][LUT_PARAM_ALPHA_BB] << 12) | 0x1;
- wl12xx_reg_write32(wl, 0x00305854, tmp);
+ wl1251_reg_write32(wl, 0x00305854, tmp);
/*
* set the calibration stop time after holdoff time expires and set
* settling time HOLD_OFF_TIME_BB
*/
tmp = LUT[ref_freq][LUT_PARAM_STOP_TIME_BB] | 0x000A0000;
- wl12xx_reg_write32(wl, 0x00305858, tmp);
+ wl1251_reg_write32(wl, 0x00305858, tmp);
/*
* set BB PLL Loop filter capacitor3- BB_C3[2:0] and set BB PLL
@@ -193,7 +193,7 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* BB_ILOOPF[7:3]
*/
tmp = LUT[ref_freq][LUT_PARAM_BB_PLL_LOOP_FILTER] | 0x00000030;
- wl12xx_reg_write32(wl, 0x003058f8, tmp);
+ wl1251_reg_write32(wl, 0x003058f8, tmp);
/*
* set regulator output voltage for n divider to
@@ -201,10 +201,10 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
* set BB PLL Loop filter capacitor2- BB_C2[7:5], set gain of BB
* PLL auto-call to normal mode- BB_CALGAIN_3DB[8]
*/
- wl12xx_reg_write32(wl, 0x003058f0, 0x29);
+ wl1251_reg_write32(wl, 0x003058f0, 0x29);
/* enable restart wakeup sequence (ELP_CMD[0]) */
- wl12xx_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
+ wl1251_reg_write32(wl, ELP_CMD, elp_cmd | 0x1);
/* restart sequence completed */
udelay(2000);
@@ -212,19 +212,19 @@ int wl12xx_boot_init_seq(struct wl12xx *wl)
return 0;
}
-int wl12xx_boot_run_firmware(struct wl12xx *wl)
+int wl1251_boot_run_firmware(struct wl1251 *wl)
{
int loop, ret;
u32 chip_id, interrupt;
wl->chip.op_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT);
- chip_id = wl12xx_reg_read32(wl, CHIP_ID_B);
+ chip_id = wl1251_reg_read32(wl, CHIP_ID_B);
- wl12xx_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
+ wl1251_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id);
if (chip_id != wl->chip.id) {
- wl12xx_error("chip id doesn't match after firmware boot");
+ wl1251_error("chip id doesn't match after firmware boot");
return -EIO;
}
@@ -232,63 +232,65 @@ int wl12xx_boot_run_firmware(struct wl12xx *wl)
loop = 0;
while (loop++ < INIT_LOOP) {
udelay(INIT_LOOP_DELAY);
- interrupt = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ interrupt = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
if (interrupt == 0xffffffff) {
- wl12xx_error("error reading hardware complete "
+ wl1251_error("error reading hardware complete "
"init indication");
return -EIO;
}
/* check that ACX_INTR_INIT_COMPLETE is enabled */
else if (interrupt & wl->chip.intr_init_complete) {
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
wl->chip.intr_init_complete);
break;
}
}
if (loop >= INIT_LOOP) {
- wl12xx_error("timeout waiting for the hardware to "
+ wl1251_error("timeout waiting for the hardware to "
"complete initialization");
return -EIO;
}
/* get hardware config command mail box */
- wl->cmd_box_addr = wl12xx_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
+ wl->cmd_box_addr = wl1251_reg_read32(wl, REG_COMMAND_MAILBOX_PTR);
/* get hardware config event mail box */
- wl->event_box_addr = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->event_box_addr = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
/* set the working partition to its "running" mode offset */
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
wl->chip.p_table[PART_WORK].mem.start,
wl->chip.p_table[PART_WORK].mem.size,
wl->chip.p_table[PART_WORK].reg.start,
wl->chip.p_table[PART_WORK].reg.size);
- wl12xx_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
+ wl1251_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x event_box_addr 0x%x",
wl->cmd_box_addr, wl->event_box_addr);
+ wl->chip.op_fw_version(wl);
+
/*
* in case of full asynchronous mode the firmware event must be
* ready to receive event from the command mailbox
*/
/* enable gpio interrupts */
- wl12xx_boot_enable_interrupts(wl);
+ wl1251_boot_enable_interrupts(wl);
wl->chip.op_target_enable_interrupts(wl);
/* unmask all mbox events */
wl->event_mask = 0xffffffff;
- ret = wl12xx_event_unmask(wl);
+ ret = wl1251_event_unmask(wl);
if (ret < 0) {
- wl12xx_error("EVENT mask setting failed");
+ wl1251_error("EVENT mask setting failed");
return ret;
}
- wl12xx_event_mbox_config(wl);
+ wl1251_event_mbox_config(wl);
/* firmware startup completed */
return 0;
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/wl1251_boot.h
index 4fa73132baa..798362d71e3 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/wl1251_boot.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -24,12 +24,12 @@
#ifndef __BOOT_H__
#define __BOOT_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_boot_soft_reset(struct wl12xx *wl);
-int wl12xx_boot_init_seq(struct wl12xx *wl);
-int wl12xx_boot_run_firmware(struct wl12xx *wl);
-void wl12xx_boot_target_enable_interrupts(struct wl12xx *wl);
+int wl1251_boot_soft_reset(struct wl1251 *wl);
+int wl1251_boot_init_seq(struct wl1251 *wl);
+int wl1251_boot_run_firmware(struct wl1251 *wl);
+void wl1251_boot_target_enable_interrupts(struct wl1251 *wl);
/* number of times we try to read the INIT interrupt */
#define INIT_LOOP 20000
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.c b/drivers/net/wireless/wl12xx/wl1251_cmd.c
new file mode 100644
index 00000000000..dc04d1fc2ee
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.c
@@ -0,0 +1,428 @@
+#include "wl1251_cmd.h"
+
+#include <linux/module.h>
+#include <linux/crc7.h>
+#include <linux/spi/spi.h>
+
+#include "wl1251.h"
+#include "reg.h"
+#include "wl1251_spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_acx.h"
+
+/**
+ * send command to firmware
+ *
+ * @wl: wl struct
+ * @id: command id
+ * @buf: buffer containing the command, must work with dma
+ * @len: length of the buffer
+ */
+int wl1251_cmd_send(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct wl1251_cmd_header *cmd;
+ unsigned long timeout;
+ u32 intr;
+ int ret = 0;
+
+ cmd = buf;
+ cmd->id = id;
+ cmd->status = 0;
+
+ WARN_ON(len % 4 != 0);
+
+ wl1251_spi_mem_write(wl, wl->cmd_box_addr, buf, len);
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
+
+ timeout = jiffies + msecs_to_jiffies(WL1251_COMMAND_TIMEOUT);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ while (!(intr & wl->chip.intr_cmd_complete)) {
+ if (time_after(jiffies, timeout)) {
+ wl1251_error("command complete timeout");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ msleep(1);
+
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
+ }
+
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_ACK,
+ wl->chip.intr_cmd_complete);
+
+out:
+ return ret;
+}
+
+/**
+ * send test command to firmware
+ *
+ * @wl: wl struct
+ * @buf: buffer containing the command, with all headers, must work with dma
+ * @len: length of the buffer
+ * @answer: is answer needed
+ */
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer)
+{
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd test");
+
+ ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len);
+
+ if (ret < 0) {
+ wl1251_warning("TEST command failed");
+ return ret;
+ }
+
+ if (answer) {
+ struct wl1251_command *cmd_answer;
+
+ /*
+ * The test command got in, we can read the answer.
+ * The answer would be a wl1251_command, where the
+ * parameter array contains the actual answer.
+ */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, buf_len);
+
+ cmd_answer = buf;
+
+ if (cmd_answer->header.status != CMD_STATUS_SUCCESS)
+ wl1251_error("TEST command answer error: %d",
+ cmd_answer->header.status);
+ }
+
+ return 0;
+}
+
+/**
+ * read acx from firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer for the response, including all headers, must work with dma
+ * @len: lenght of buf
+ */
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd interrogate");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1251_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1251_error("INTERROGATE command failed");
+ goto out;
+ }
+
+ /* the interrogate command got in, we can read the answer */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, buf, len);
+
+ acx = buf;
+ if (acx->cmd.status != CMD_STATUS_SUCCESS)
+ wl1251_error("INTERROGATE command error: %d",
+ acx->cmd.status);
+
+out:
+ return ret;
+}
+
+/**
+ * write acx value to firmware
+ *
+ * @wl: wl struct
+ * @id: acx id
+ * @buf: buffer containing acx, including all headers, must work with dma
+ * @len: length of buf
+ */
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len)
+{
+ struct acx_header *acx = buf;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd configure");
+
+ acx->id = id;
+
+ /* payload length, does not include any headers */
+ acx->len = len - sizeof(*acx);
+
+ ret = wl1251_cmd_send(wl, CMD_CONFIGURE, acx, len);
+ if (ret < 0) {
+ wl1251_warning("CONFIGURE command NOK");
+ return ret;
+ }
+
+ return 0;
+}
+
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
+ void *bitmap, u16 bitmap_len, u8 bitmap_control)
+{
+ struct wl1251_cmd_vbm_update *vbm;
+ int ret;
+
+ wl1251_debug(DEBUG_CMD, "cmd vbm");
+
+ vbm = kzalloc(sizeof(*vbm), GFP_KERNEL);
+ if (!vbm) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Count and period will be filled by the target */
+ vbm->tim.bitmap_ctrl = bitmap_control;
+ if (bitmap_len > PARTIAL_VBM_MAX) {
+ wl1251_warning("cmd vbm len is %d B, truncating to %d",
+ bitmap_len, PARTIAL_VBM_MAX);
+ bitmap_len = PARTIAL_VBM_MAX;
+ }
+ memcpy(vbm->tim.pvb_field, bitmap, bitmap_len);
+ vbm->tim.identity = identity;
+ vbm->tim.length = bitmap_len + 3;
+
+ vbm->len = cpu_to_le16(bitmap_len + 5);
+
+ ret = wl1251_cmd_send(wl, CMD_VBM, vbm, sizeof(*vbm));
+ if (ret < 0) {
+ wl1251_error("VBM command failed");
+ goto out;
+ }
+
+out:
+ kfree(vbm);
+ return 0;
+}
+
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
+{
+ struct cmd_enabledisable_path *cmd;
+ int ret;
+ u16 cmd_rx, cmd_tx;
+
+ wl1251_debug(DEBUG_CMD, "cmd data path");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->channel = channel;
+
+ if (enable) {
+ cmd_rx = CMD_ENABLE_RX;
+ cmd_tx = CMD_ENABLE_TX;
+ } else {
+ cmd_rx = CMD_DISABLE_RX;
+ cmd_tx = CMD_DISABLE_TX;
+ }
+
+ ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("rx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+ ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("tx %s cmd for channel %d failed",
+ enable ? "start" : "stop", channel);
+ return ret;
+ }
+
+ wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
+ enable ? "start" : "stop", channel);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
+ u16 beacon_interval, u8 wait)
+{
+ unsigned long timeout;
+ struct cmd_join *join;
+ int ret, i;
+ u8 *bssid;
+
+ join = kzalloc(sizeof(*join), GFP_KERNEL);
+ if (!join) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* FIXME: this should be in main.c */
+ ret = wl1251_acx_frame_rates(wl, DEFAULT_HW_GEN_TX_RATE,
+ DEFAULT_HW_GEN_MODULATION_TYPE,
+ wl->tx_mgmt_frm_rate,
+ wl->tx_mgmt_frm_mod);
+ if (ret < 0)
+ goto out;
+
+ wl1251_debug(DEBUG_CMD, "cmd join");
+
+ /* Reverse order BSSID */
+ bssid = (u8 *) &join->bssid_lsb;
+ for (i = 0; i < ETH_ALEN; i++)
+ bssid[i] = wl->bssid[ETH_ALEN - i - 1];
+
+ join->rx_config_options = wl->rx_config;
+ join->rx_filter_options = wl->rx_filter;
+
+ join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS |
+ RATE_MASK_5_5MBPS | RATE_MASK_11MBPS;
+
+ join->beacon_interval = beacon_interval;
+ join->dtim_interval = dtim_interval;
+ join->bss_type = bss_type;
+ join->channel = wl->channel;
+ join->ctrl = JOIN_CMD_CTRL_TX_FLUSH;
+
+ ret = wl1251_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join));
+ if (ret < 0) {
+ wl1251_error("failed to initiate cmd join");
+ goto out;
+ }
+
+ timeout = msecs_to_jiffies(JOIN_TIMEOUT);
+
+ /*
+ * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to
+ * simplify locking we just sleep instead, for now
+ */
+ if (wait)
+ msleep(10);
+
+out:
+ kfree(join);
+ return ret;
+}
+
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode)
+{
+ struct wl1251_cmd_ps_params *ps_params = NULL;
+ int ret = 0;
+
+ /* FIXME: this should be in ps.c */
+ ret = wl1251_acx_wake_up_conditions(wl, WAKE_UP_EVENT_DTIM_BITMAP,
+ wl->listen_int);
+ if (ret < 0) {
+ wl1251_error("couldn't set wake up conditions");
+ goto out;
+ }
+
+ wl1251_debug(DEBUG_CMD, "cmd set ps mode");
+
+ ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
+ if (!ps_params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ps_params->ps_mode = ps_mode;
+ ps_params->send_null_data = 1;
+ ps_params->retries = 5;
+ ps_params->hang_over_period = 128;
+ ps_params->null_data_rate = 1; /* 1 Mbps */
+
+ ret = wl1251_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
+ sizeof(*ps_params));
+ if (ret < 0) {
+ wl1251_error("cmd set_ps_mode failed");
+ goto out;
+ }
+
+out:
+ kfree(ps_params);
+ return ret;
+}
+
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+ size_t len)
+{
+ struct cmd_read_write_memory *cmd;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd read memory");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ WARN_ON(len > MAX_READ_SIZE);
+ len = min_t(size_t, len, MAX_READ_SIZE);
+
+ cmd->addr = addr;
+ cmd->size = len;
+
+ ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd));
+ if (ret < 0) {
+ wl1251_error("read memory command failed: %d", ret);
+ goto out;
+ }
+
+ /* the read command got in, we can now read the answer */
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd));
+
+ if (cmd->header.status != CMD_STATUS_SUCCESS)
+ wl1251_error("error in read command result: %d",
+ cmd->header.status);
+
+ memcpy(answer, cmd->value, len);
+
+out:
+ kfree(cmd);
+ return ret;
+}
+
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
+ void *buf, size_t buf_len)
+{
+ struct wl1251_cmd_packet_template *cmd;
+ size_t cmd_len;
+ int ret = 0;
+
+ wl1251_debug(DEBUG_CMD, "cmd template %d", cmd_id);
+
+ WARN_ON(buf_len > WL1251_MAX_TEMPLATE_SIZE);
+ buf_len = min_t(size_t, buf_len, WL1251_MAX_TEMPLATE_SIZE);
+ cmd_len = ALIGN(sizeof(*cmd) + buf_len, 4);
+
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (!cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cmd->size = cpu_to_le16(buf_len);
+
+ if (buf)
+ memcpy(cmd->data, buf, buf_len);
+
+ ret = wl1251_cmd_send(wl, cmd_id, cmd, cmd_len);
+ if (ret < 0) {
+ wl1251_warning("cmd set_template failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index aa307dcd081..64f228dd9a9 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,37 +22,32 @@
*
*/
-#ifndef __WL12XX_CMD_H__
-#define __WL12XX_CMD_H__
+#ifndef __WL1251_CMD_H__
+#define __WL1251_CMD_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_cmd_send(struct wl12xx *wl, u16 type, void *buf, size_t buf_len);
-int wl12xx_cmd_test(struct wl12xx *wl, void *buf, size_t buf_len, u8 answer);
-int wl12xx_cmd_interrogate(struct wl12xx *wl, u16 ie_id, u16 ie_len,
- void *answer);
-int wl12xx_cmd_configure(struct wl12xx *wl, void *ie, int ie_len);
-int wl12xx_cmd_vbm(struct wl12xx *wl, u8 identity,
+struct acx_header;
+
+int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len);
+int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer);
+int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len);
+int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
void *bitmap, u16 bitmap_len, u8 bitmap_control);
-int wl12xx_cmd_data_path(struct wl12xx *wl, u8 channel, u8 enable);
-int wl12xx_cmd_join(struct wl12xx *wl, u8 bss_type, u8 dtim_interval,
+int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 dtim_interval,
u16 beacon_interval, u8 wait);
-int wl12xx_cmd_ps_mode(struct wl12xx *wl, u8 ps_mode);
-int wl12xx_cmd_read_memory(struct wl12xx *wl, u32 addr, u32 len, void *answer);
-int wl12xx_cmd_template_set(struct wl12xx *wl, u16 cmd_id,
+int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode);
+int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer,
+ size_t len);
+int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id,
void *buf, size_t buf_len);
/* unit ms */
-#define WL12XX_COMMAND_TIMEOUT 2000
-
-#define WL12XX_MAX_TEMPLATE_SIZE 300
+#define WL1251_COMMAND_TIMEOUT 2000
-struct wl12xx_cmd_packet_template {
- __le16 size;
- u8 template[WL12XX_MAX_TEMPLATE_SIZE];
-} __attribute__ ((packed));
-
-enum wl12xx_commands {
+enum wl1251_commands {
CMD_RESET = 0,
CMD_INTERROGATE = 1, /*use this to read information elements*/
CMD_CONFIGURE = 2, /*use this to write information elements*/
@@ -100,9 +95,15 @@ enum wl12xx_commands {
#define MAX_CMD_PARAMS 572
-struct wl12xx_command {
+struct wl1251_cmd_header {
u16 id;
u16 status;
+ /* payload */
+ u8 data[0];
+} __attribute__ ((packed));
+
+struct wl1251_command {
+ struct wl1251_cmd_header header;
u8 parameters[MAX_CMD_PARAMS];
};
@@ -144,6 +145,8 @@ enum {
#define MAX_READ_SIZE 256
struct cmd_read_write_memory {
+ struct wl1251_cmd_header header;
+
/* The address of the memory to read from or write to.*/
u32 addr;
@@ -211,6 +214,8 @@ struct basic_scan_channel_parameters {
#define SCAN_MAX_NUM_OF_CHANNELS 16
struct cmd_scan {
+ struct wl1251_cmd_header header;
+
struct basic_scan_parameters params;
struct basic_scan_channel_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
} __attribute__ ((packed));
@@ -227,6 +232,8 @@ enum {
struct cmd_join {
+ struct wl1251_cmd_header header;
+
u32 bssid_lsb;
u16 bssid_msb;
u16 beacon_interval; /* in TBTTs */
@@ -261,5 +268,140 @@ struct cmd_join {
u8 reserved;
} __attribute__ ((packed));
+struct cmd_enabledisable_path {
+ struct wl1251_cmd_header header;
+
+ u8 channel;
+ u8 padding[3];
+} __attribute__ ((packed));
+
+#define WL1251_MAX_TEMPLATE_SIZE 300
+
+struct wl1251_cmd_packet_template {
+ struct wl1251_cmd_header header;
+
+ __le16 size;
+ u8 data[0];
+} __attribute__ ((packed));
+
+#define TIM_ELE_ID 5
+#define PARTIAL_VBM_MAX 251
+
+struct wl1251_tim {
+ u8 identity;
+ u8 length;
+ u8 dtim_count;
+ u8 dtim_period;
+ u8 bitmap_ctrl;
+ u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
+} __attribute__ ((packed));
+
+/* Virtual Bit Map update */
+struct wl1251_cmd_vbm_update {
+ struct wl1251_cmd_header header;
+ __le16 len;
+ u8 padding[2];
+ struct wl1251_tim tim;
+} __attribute__ ((packed));
+
+enum wl1251_cmd_ps_mode {
+ STATION_ACTIVE_MODE,
+ STATION_POWER_SAVE_MODE
+};
+
+struct wl1251_cmd_ps_params {
+ struct wl1251_cmd_header header;
+
+ u8 ps_mode; /* STATION_* */
+ u8 send_null_data; /* Do we have to send NULL data packet ? */
+ u8 retries; /* Number of retires for the initial NULL data packet */
+
+ /*
+ * TUs during which the target stays awake after switching
+ * to power save mode.
+ */
+ u8 hang_over_period;
+ u16 null_data_rate;
+ u8 pad[2];
+} __attribute__ ((packed));
+
+struct wl1251_cmd_trigger_scan_to {
+ struct wl1251_cmd_header header;
+
+ u32 timeout;
+};
+
+/* HW encryption keys */
+#define NUM_ACCESS_CATEGORIES_COPY 4
+#define MAX_KEY_SIZE 32
+
+/* When set, disable HW encryption */
+#define DF_ENCRYPTION_DISABLE 0x01
+/* When set, disable HW decryption */
+#define DF_SNIFF_MODE_ENABLE 0x80
+
+enum wl1251_cmd_key_action {
+ KEY_ADD_OR_REPLACE = 1,
+ KEY_REMOVE = 2,
+ KEY_SET_ID = 3,
+ MAX_KEY_ACTION = 0xffff,
+};
+
+enum wl1251_cmd_key_type {
+ KEY_WEP_DEFAULT = 0,
+ KEY_WEP_ADDR = 1,
+ KEY_AES_GROUP = 4,
+ KEY_AES_PAIRWISE = 5,
+ KEY_WEP_GROUP = 6,
+ KEY_TKIP_MIC_GROUP = 10,
+ KEY_TKIP_MIC_PAIRWISE = 11,
+};
+
+/*
+ *
+ * key_type_e key size key format
+ * ---------- --------- ----------
+ * 0x00 5, 13, 29 Key data
+ * 0x01 5, 13, 29 Key data
+ * 0x04 16 16 bytes of key data
+ * 0x05 16 16 bytes of key data
+ * 0x0a 32 16 bytes of TKIP key data
+ * 8 bytes of RX MIC key data
+ * 8 bytes of TX MIC key data
+ * 0x0b 32 16 bytes of TKIP key data
+ * 8 bytes of RX MIC key data
+ * 8 bytes of TX MIC key data
+ *
+ */
+
+struct wl1251_cmd_set_keys {
+ struct wl1251_cmd_header header;
+
+ /* Ignored for default WEP key */
+ u8 addr[ETH_ALEN];
+
+ /* key_action_e */
+ u16 key_action;
+
+ u16 reserved_1;
+
+ /* key size in bytes */
+ u8 key_size;
+
+ /* key_type_e */
+ u8 key_type;
+ u8 ssid_profile;
+
+ /*
+ * TKIP, AES: frame's key id field.
+ * For WEP default key: key id;
+ */
+ u8 id;
+ u8 reserved_2[6];
+ u8 key[MAX_KEY_SIZE];
+ u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
+ u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
+} __attribute__ ((packed));
+
-#endif /* __WL12XX_CMD_H__ */
+#endif /* __WL1251_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
index cdb368ce4da..a00723059f8 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,15 +21,16 @@
*
*/
-#include "debugfs.h"
+#include "wl1251_debugfs.h"
#include <linux/skbuff.h>
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
+#include "wl1251_ps.h"
/* ms */
-#define WL12XX_DEBUGFS_STATS_LIFETIME 1000
+#define WL1251_DEBUGFS_STATS_LIFETIME 1000
/* debugfs macros idea from mac80211 */
@@ -37,7 +38,7 @@
static ssize_t name## _read(struct file *file, char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
- struct wl12xx *wl = file->private_data; \
+ struct wl1251 *wl = file->private_data; \
char buf[buflen]; \
int res; \
\
@@ -47,7 +48,7 @@ static ssize_t name## _read(struct file *file, char __user *userbuf, \
\
static const struct file_operations name## _ops = { \
.read = name## _read, \
- .open = wl12xx_open_file_generic, \
+ .open = wl1251_open_file_generic, \
};
#define DEBUGFS_ADD(name, parent) \
@@ -70,11 +71,11 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
char __user *userbuf, \
size_t count, loff_t *ppos) \
{ \
- struct wl12xx *wl = file->private_data; \
+ struct wl1251 *wl = file->private_data; \
char buf[buflen]; \
int res; \
\
- wl12xx_debugfs_update_stats(wl); \
+ wl1251_debugfs_update_stats(wl); \
\
res = scnprintf(buf, buflen, fmt "\n", \
wl->stats.fw_stats->sub.name); \
@@ -83,7 +84,7 @@ static ssize_t sub## _ ##name## _read(struct file *file, \
\
static const struct file_operations sub## _ ##name## _ops = { \
.read = sub## _ ##name## _read, \
- .open = wl12xx_open_file_generic, \
+ .open = wl1251_open_file_generic, \
};
#define DEBUGFS_FWSTATS_ADD(sub, name) \
@@ -92,21 +93,30 @@ static const struct file_operations sub## _ ##name## _ops = { \
#define DEBUGFS_FWSTATS_DEL(sub, name) \
DEBUGFS_DEL(sub## _ ##name)
-static void wl12xx_debugfs_update_stats(struct wl12xx *wl)
+static void wl1251_debugfs_update_stats(struct wl1251 *wl)
{
+ int ret;
+
mutex_lock(&wl->mutex);
- if (wl->state == WL12XX_STATE_ON &&
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ if (wl->state == WL1251_STATE_ON &&
time_after(jiffies, wl->stats.fw_stats_update +
- msecs_to_jiffies(WL12XX_DEBUGFS_STATS_LIFETIME))) {
- wl12xx_acx_statistics(wl, wl->stats.fw_stats);
+ msecs_to_jiffies(WL1251_DEBUGFS_STATS_LIFETIME))) {
+ wl1251_acx_statistics(wl, wl->stats.fw_stats);
wl->stats.fw_stats_update = jiffies;
}
+ wl1251_ps_elp_sleep(wl);
+
+out:
mutex_unlock(&wl->mutex);
}
-static int wl12xx_open_file_generic(struct inode *inode, struct file *file)
+static int wl1251_open_file_generic(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
@@ -211,7 +221,7 @@ DEBUGFS_READONLY_FILE(excessive_retries, 20, "%u",
static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- struct wl12xx *wl = file->private_data;
+ struct wl1251 *wl = file->private_data;
u32 queue_len;
char buf[20];
int res;
@@ -224,10 +234,10 @@ static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
static const struct file_operations tx_queue_len_ops = {
.read = tx_queue_len_read,
- .open = wl12xx_open_file_generic,
+ .open = wl1251_open_file_generic,
};
-static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
+static void wl1251_debugfs_delete_files(struct wl1251 *wl)
{
DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow);
@@ -325,7 +335,7 @@ static void wl12xx_debugfs_delete_files(struct wl12xx *wl)
DEBUGFS_DEL(excessive_retries);
}
-static int wl12xx_debugfs_add_files(struct wl12xx *wl)
+static int wl1251_debugfs_add_files(struct wl1251 *wl)
{
int ret = 0;
@@ -426,19 +436,19 @@ static int wl12xx_debugfs_add_files(struct wl12xx *wl)
out:
if (ret < 0)
- wl12xx_debugfs_delete_files(wl);
+ wl1251_debugfs_delete_files(wl);
return ret;
}
-void wl12xx_debugfs_reset(struct wl12xx *wl)
+void wl1251_debugfs_reset(struct wl1251 *wl)
{
memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats));
wl->stats.retry_count = 0;
wl->stats.excessive_retries = 0;
}
-int wl12xx_debugfs_init(struct wl12xx *wl)
+int wl1251_debugfs_init(struct wl1251 *wl)
{
int ret;
@@ -469,7 +479,7 @@ int wl12xx_debugfs_init(struct wl12xx *wl)
wl->stats.fw_stats_update = jiffies;
- ret = wl12xx_debugfs_add_files(wl);
+ ret = wl1251_debugfs_add_files(wl);
if (ret < 0)
goto err_file;
@@ -492,9 +502,9 @@ err:
return ret;
}
-void wl12xx_debugfs_exit(struct wl12xx *wl)
+void wl1251_debugfs_exit(struct wl1251 *wl)
{
- wl12xx_debugfs_delete_files(wl);
+ wl1251_debugfs_delete_files(wl);
kfree(wl->stats.fw_stats);
wl->stats.fw_stats = NULL;
diff --git a/drivers/net/wireless/wl12xx/debugfs.h b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
index 562cdcbcc87..6dc3d080853 100644
--- a/drivers/net/wireless/wl12xx/debugfs.h
+++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,13 +21,13 @@
*
*/
-#ifndef WL12XX_DEBUGFS_H
-#define WL12XX_DEBUGFS_H
+#ifndef WL1251_DEBUGFS_H
+#define WL1251_DEBUGFS_H
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_debugfs_init(struct wl12xx *wl);
-void wl12xx_debugfs_exit(struct wl12xx *wl);
-void wl12xx_debugfs_reset(struct wl12xx *wl);
+int wl1251_debugfs_init(struct wl1251 *wl);
+void wl1251_debugfs_exit(struct wl1251 *wl);
+void wl1251_debugfs_reset(struct wl1251 *wl);
-#endif /* WL12XX_DEBUGFS_H */
+#endif /* WL1251_DEBUGFS_H */
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/wl1251_event.c
index 99529ca89a7..1a0a0bc1a31 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/wl1251_event.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,16 +22,16 @@
*
*/
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "event.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_ps.h"
-static int wl12xx_event_scan_complete(struct wl12xx *wl,
+static int wl1251_event_scan_complete(struct wl1251 *wl,
struct event_mailbox *mbox)
{
- wl12xx_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
+ wl1251_debug(DEBUG_EVENT, "status: 0x%x, channels: %d",
mbox->scheduled_scan_status,
mbox->scheduled_scan_channels);
@@ -45,34 +45,34 @@ static int wl12xx_event_scan_complete(struct wl12xx *wl,
return 0;
}
-static void wl12xx_event_mbox_dump(struct event_mailbox *mbox)
+static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
{
- wl12xx_debug(DEBUG_EVENT, "MBOX DUMP:");
- wl12xx_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
- wl12xx_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
+ wl1251_debug(DEBUG_EVENT, "MBOX DUMP:");
+ wl1251_debug(DEBUG_EVENT, "\tvector: 0x%x", mbox->events_vector);
+ wl1251_debug(DEBUG_EVENT, "\tmask: 0x%x", mbox->events_mask);
}
-static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
+static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
{
int ret;
u32 vector;
- wl12xx_event_mbox_dump(mbox);
+ wl1251_event_mbox_dump(mbox);
vector = mbox->events_vector & ~(mbox->events_mask);
- wl12xx_debug(DEBUG_EVENT, "vector: 0x%x", vector);
+ wl1251_debug(DEBUG_EVENT, "vector: 0x%x", vector);
if (vector & SCAN_COMPLETE_EVENT_ID) {
- ret = wl12xx_event_scan_complete(wl, mbox);
+ ret = wl1251_event_scan_complete(wl, mbox);
if (ret < 0)
return ret;
}
if (vector & BSS_LOSE_EVENT_ID) {
- wl12xx_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
+ wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
if (wl->psm_requested && wl->psm) {
- ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
}
@@ -81,47 +81,47 @@ static int wl12xx_event_process(struct wl12xx *wl, struct event_mailbox *mbox)
return 0;
}
-int wl12xx_event_unmask(struct wl12xx *wl)
+int wl1251_event_unmask(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_event_mbox_mask(wl, ~(wl->event_mask));
+ ret = wl1251_acx_event_mbox_mask(wl, ~(wl->event_mask));
if (ret < 0)
return ret;
return 0;
}
-void wl12xx_event_mbox_config(struct wl12xx *wl)
+void wl1251_event_mbox_config(struct wl1251 *wl)
{
- wl->mbox_ptr[0] = wl12xx_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
+ wl->mbox_ptr[0] = wl1251_reg_read32(wl, REG_EVENT_MAILBOX_PTR);
wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox);
- wl12xx_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
+ wl1251_debug(DEBUG_EVENT, "MBOX ptrs: 0x%x 0x%x",
wl->mbox_ptr[0], wl->mbox_ptr[1]);
}
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox_num)
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox_num)
{
struct event_mailbox mbox;
int ret;
- wl12xx_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
+ wl1251_debug(DEBUG_EVENT, "EVENT on mbox %d", mbox_num);
if (mbox_num > 1)
return -EINVAL;
/* first we read the mbox descriptor */
- wl12xx_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
+ wl1251_spi_mem_read(wl, wl->mbox_ptr[mbox_num], &mbox,
sizeof(struct event_mailbox));
/* process the descriptor */
- ret = wl12xx_event_process(wl, &mbox);
+ ret = wl1251_event_process(wl, &mbox);
if (ret < 0)
return ret;
/* then we let the firmware know it can go on...*/
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK);
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/wl1251_event.h
index 1f4c2f7438a..be0ac54d624 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/wl1251_event.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL12XX_EVENT_H__
-#define __WL12XX_EVENT_H__
+#ifndef __WL1251_EVENT_H__
+#define __WL1251_EVENT_H__
/*
* Mbox events
@@ -114,8 +114,8 @@ struct event_mailbox {
u8 padding[19];
} __attribute__ ((packed));
-int wl12xx_event_unmask(struct wl12xx *wl);
-void wl12xx_event_mbox_config(struct wl12xx *wl);
-int wl12xx_event_handle(struct wl12xx *wl, u8 mbox);
+int wl1251_event_unmask(struct wl1251 *wl);
+void wl1251_event_mbox_config(struct wl1251 *wl);
+int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
#endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/wl1251_init.c
index 2a573a6010b..df6c60f0fd6 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/wl1251_init.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -24,64 +24,64 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "init.h"
+#include "wl1251_init.h"
#include "wl12xx_80211.h"
-#include "acx.h"
-#include "cmd.h"
+#include "wl1251_acx.h"
+#include "wl1251_cmd.h"
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl)
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_feature_cfg(wl);
+ ret = wl1251_acx_feature_cfg(wl);
if (ret < 0) {
- wl12xx_warning("couldn't set feature config");
+ wl1251_warning("couldn't set feature config");
return ret;
}
- ret = wl12xx_acx_default_key(wl, wl->default_key);
+ ret = wl1251_acx_default_key(wl, wl->default_key);
if (ret < 0) {
- wl12xx_warning("couldn't set default key");
+ wl1251_warning("couldn't set default key");
return ret;
}
return 0;
}
-int wl12xx_hw_init_templates_config(struct wl12xx *wl)
+int wl1251_hw_init_templates_config(struct wl1251 *wl)
{
int ret;
u8 partial_vbm[PARTIAL_VBM_MAX];
/* send empty templates for fw memory reservation */
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_REQ, NULL,
sizeof(struct wl12xx_probe_req_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_NULL_DATA, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_NULL_DATA, NULL,
sizeof(struct wl12xx_null_data_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_PS_POLL, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PS_POLL, NULL,
sizeof(struct wl12xx_ps_poll_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_QOS_NULL_DATA, NULL,
sizeof
(struct wl12xx_qos_null_data_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, NULL,
sizeof
(struct wl12xx_probe_resp_template));
if (ret < 0)
return ret;
- ret = wl12xx_cmd_template_set(wl, CMD_BEACON, NULL,
+ ret = wl1251_cmd_template_set(wl, CMD_BEACON, NULL,
sizeof
(struct wl12xx_beacon_template));
if (ret < 0)
@@ -89,112 +89,112 @@ int wl12xx_hw_init_templates_config(struct wl12xx *wl)
/* tim templates, first reserve space then allocate an empty one */
memset(partial_vbm, 0, PARTIAL_VBM_MAX);
- ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
+ ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, PARTIAL_VBM_MAX, 0);
if (ret < 0)
return ret;
- ret = wl12xx_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
+ ret = wl1251_cmd_vbm(wl, TIM_ELE_ID, partial_vbm, 1, 0);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter)
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter)
{
int ret;
- ret = wl12xx_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
+ ret = wl1251_acx_rx_msdu_life_time(wl, RX_MSDU_LIFETIME_DEF);
if (ret < 0)
return ret;
- ret = wl12xx_acx_rx_config(wl, config, filter);
+ ret = wl1251_acx_rx_config(wl, config, filter);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_phy_config(struct wl12xx *wl)
+int wl1251_hw_init_phy_config(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_pd_threshold(wl);
+ ret = wl1251_acx_pd_threshold(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_slot(wl, DEFAULT_SLOT_TIME);
+ ret = wl1251_acx_slot(wl, DEFAULT_SLOT_TIME);
if (ret < 0)
return ret;
- ret = wl12xx_acx_group_address_tbl(wl);
+ ret = wl1251_acx_group_address_tbl(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_service_period_timeout(wl);
+ ret = wl1251_acx_service_period_timeout(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
+ ret = wl1251_acx_rts_threshold(wl, RTS_THRESHOLD_DEF);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl)
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_beacon_filter_opt(wl);
+ ret = wl1251_acx_beacon_filter_opt(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_beacon_filter_table(wl);
+ ret = wl1251_acx_beacon_filter_table(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_pta(struct wl12xx *wl)
+int wl1251_hw_init_pta(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_sg_enable(wl);
+ ret = wl1251_acx_sg_enable(wl);
if (ret < 0)
return ret;
- ret = wl12xx_acx_sg_cfg(wl);
+ ret = wl1251_acx_sg_cfg(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl)
+int wl1251_hw_init_energy_detection(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_cca_threshold(wl);
+ ret = wl1251_acx_cca_threshold(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl)
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl)
{
int ret;
- ret = wl12xx_acx_bcn_dtim_options(wl);
+ ret = wl1251_acx_bcn_dtim_options(wl);
if (ret < 0)
return ret;
return 0;
}
-int wl12xx_hw_init_power_auth(struct wl12xx *wl)
+int wl1251_hw_init_power_auth(struct wl1251 *wl)
{
- return wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+ return wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
}
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/wl1251_init.h
index c8b6cd0b7c3..8596188e834 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/wl1251_init.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2009 Nokia Corporation
*
@@ -21,20 +21,19 @@
*
*/
-#ifndef __WL12XX_INIT_H__
-#define __WL12XX_INIT_H__
+#ifndef __WL1251_INIT_H__
+#define __WL1251_INIT_H__
-#include "wl12xx.h"
+#include "wl1251.h"
-int wl12xx_hw_init_hwenc_config(struct wl12xx *wl);
-int wl12xx_hw_init_templates_config(struct wl12xx *wl);
-int wl12xx_hw_init_mem_config(struct wl12xx *wl);
-int wl12xx_hw_init_rx_config(struct wl12xx *wl, u32 config, u32 filter);
-int wl12xx_hw_init_phy_config(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_filter(struct wl12xx *wl);
-int wl12xx_hw_init_pta(struct wl12xx *wl);
-int wl12xx_hw_init_energy_detection(struct wl12xx *wl);
-int wl12xx_hw_init_beacon_broadcast(struct wl12xx *wl);
-int wl12xx_hw_init_power_auth(struct wl12xx *wl);
+int wl1251_hw_init_hwenc_config(struct wl1251 *wl);
+int wl1251_hw_init_templates_config(struct wl1251 *wl);
+int wl1251_hw_init_rx_config(struct wl1251 *wl, u32 config, u32 filter);
+int wl1251_hw_init_phy_config(struct wl1251 *wl);
+int wl1251_hw_init_beacon_filter(struct wl1251 *wl);
+int wl1251_hw_init_pta(struct wl1251 *wl);
+int wl1251_hw_init_energy_detection(struct wl1251 *wl);
+int wl1251_hw_init_beacon_broadcast(struct wl1251 *wl);
+int wl1251_hw_init_power_auth(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 603d6114882..da4c688c46a 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008-2009 Nokia Corporation
*
@@ -31,38 +31,38 @@
#include <linux/etherdevice.h>
#include <linux/spi/wl12xx.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "wl12xx_80211.h"
#include "reg.h"
-#include "wl1251.h"
-#include "spi.h"
-#include "event.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-#include "debugfs.h"
-
-static void wl12xx_disable_interrupts(struct wl12xx *wl)
+#include "wl1251_ops.h"
+#include "wl1251_spi.h"
+#include "wl1251_event.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+#include "wl1251_debugfs.h"
+
+static void wl1251_disable_interrupts(struct wl1251 *wl)
{
disable_irq(wl->irq);
}
-static void wl12xx_power_off(struct wl12xx *wl)
+static void wl1251_power_off(struct wl1251 *wl)
{
wl->set_power(false);
}
-static void wl12xx_power_on(struct wl12xx *wl)
+static void wl1251_power_on(struct wl1251 *wl)
{
wl->set_power(true);
}
-static irqreturn_t wl12xx_irq(int irq, void *cookie)
+static irqreturn_t wl1251_irq(int irq, void *cookie)
{
- struct wl12xx *wl;
+ struct wl1251 *wl;
- wl12xx_debug(DEBUG_IRQ, "IRQ");
+ wl1251_debug(DEBUG_IRQ, "IRQ");
wl = cookie;
@@ -71,7 +71,7 @@ static irqreturn_t wl12xx_irq(int irq, void *cookie)
return IRQ_HANDLED;
}
-static int wl12xx_fetch_firmware(struct wl12xx *wl)
+static int wl1251_fetch_firmware(struct wl1251 *wl)
{
const struct firmware *fw;
int ret;
@@ -79,12 +79,12 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
ret = request_firmware(&fw, wl->chip.fw_filename, &wl->spi->dev);
if (ret < 0) {
- wl12xx_error("could not get firmware: %d", ret);
+ wl1251_error("could not get firmware: %d", ret);
return ret;
}
if (fw->size % 4) {
- wl12xx_error("firmware size is not multiple of 32 bits: %zu",
+ wl1251_error("firmware size is not multiple of 32 bits: %zu",
fw->size);
ret = -EILSEQ;
goto out;
@@ -94,7 +94,7 @@ static int wl12xx_fetch_firmware(struct wl12xx *wl)
wl->fw = kmalloc(wl->fw_len, GFP_KERNEL);
if (!wl->fw) {
- wl12xx_error("could not allocate memory for the firmware");
+ wl1251_error("could not allocate memory for the firmware");
ret = -ENOMEM;
goto out;
}
@@ -109,7 +109,7 @@ out:
return ret;
}
-static int wl12xx_fetch_nvs(struct wl12xx *wl)
+static int wl1251_fetch_nvs(struct wl1251 *wl)
{
const struct firmware *fw;
int ret;
@@ -117,12 +117,12 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
ret = request_firmware(&fw, wl->chip.nvs_filename, &wl->spi->dev);
if (ret < 0) {
- wl12xx_error("could not get nvs file: %d", ret);
+ wl1251_error("could not get nvs file: %d", ret);
return ret;
}
if (fw->size % 4) {
- wl12xx_error("nvs size is not multiple of 32 bits: %zu",
+ wl1251_error("nvs size is not multiple of 32 bits: %zu",
fw->size);
ret = -EILSEQ;
goto out;
@@ -132,7 +132,7 @@ static int wl12xx_fetch_nvs(struct wl12xx *wl)
wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
if (!wl->nvs) {
- wl12xx_error("could not allocate memory for the nvs file");
+ wl1251_error("could not allocate memory for the nvs file");
ret = -ENOMEM;
goto out;
}
@@ -147,74 +147,70 @@ out:
return ret;
}
-static void wl12xx_fw_wakeup(struct wl12xx *wl)
+static void wl1251_fw_wakeup(struct wl1251 *wl)
{
u32 elp_reg;
elp_reg = ELPCTRL_WAKE_UP;
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
- if (!(elp_reg & ELPCTRL_WLAN_READY)) {
- wl12xx_warning("WLAN not ready");
- elp_reg = ELPCTRL_WAKE_UP_WLAN_READY;
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, elp_reg);
- }
+ if (!(elp_reg & ELPCTRL_WLAN_READY))
+ wl1251_warning("WLAN not ready");
}
-static int wl12xx_chip_wakeup(struct wl12xx *wl)
+static int wl1251_chip_wakeup(struct wl1251 *wl)
{
int ret = 0;
- wl12xx_power_on(wl);
+ wl1251_power_on(wl);
msleep(wl->chip.power_on_sleep);
- wl12xx_spi_reset(wl);
- wl12xx_spi_init(wl);
+ wl1251_spi_reset(wl);
+ wl1251_spi_init(wl);
/* We don't need a real memory partition here, because we only want
* to use the registers at this point. */
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
0x00000000,
0x00000000,
REGISTERS_BASE,
REGISTERS_DOWN_SIZE);
/* ELP module wake up */
- wl12xx_fw_wakeup(wl);
+ wl1251_fw_wakeup(wl);
/* whal_FwCtrl_BootSm() */
/* 0. read chip id from CHIP_ID */
- wl->chip.id = wl12xx_reg_read32(wl, CHIP_ID_B);
+ wl->chip.id = wl1251_reg_read32(wl, CHIP_ID_B);
/* 1. check if chip id is valid */
switch (wl->chip.id) {
case CHIP_ID_1251_PG12:
- wl12xx_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
+ wl1251_debug(DEBUG_BOOT, "chip id 0x%x (1251 PG12)",
wl->chip.id);
wl1251_setup(wl);
break;
- case CHIP_ID_1271_PG10:
case CHIP_ID_1251_PG10:
case CHIP_ID_1251_PG11:
default:
- wl12xx_error("unsupported chip id: 0x%x", wl->chip.id);
+ wl1251_error("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
goto out;
}
if (wl->fw == NULL) {
- ret = wl12xx_fetch_firmware(wl);
+ ret = wl1251_fetch_firmware(wl);
if (ret < 0)
goto out;
}
/* No NVS from netlink, try to get it from the filesystem */
if (wl->nvs == NULL) {
- ret = wl12xx_fetch_nvs(wl);
+ ret = wl1251_fetch_nvs(wl);
if (ret < 0)
goto out;
}
@@ -223,88 +219,51 @@ out:
return ret;
}
-static void wl12xx_filter_work(struct work_struct *work)
+static void wl1251_filter_work(struct work_struct *work)
{
- struct wl12xx *wl =
- container_of(work, struct wl12xx, filter_work);
+ struct wl1251 *wl =
+ container_of(work, struct wl1251, filter_work);
int ret;
mutex_lock(&wl->mutex);
- if (wl->state == WL12XX_STATE_OFF)
+ if (wl->state == WL1251_STATE_OFF)
goto out;
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl1251_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
-out:
- mutex_unlock(&wl->mutex);
-}
-
-int wl12xx_plt_start(struct wl12xx *wl)
-{
- int ret;
-
- wl12xx_notice("power up");
-
- if (wl->state != WL12XX_STATE_OFF) {
- wl12xx_error("cannot go into PLT state because not "
- "in off state: %d", wl->state);
- return -EBUSY;
- }
-
- wl->state = WL12XX_STATE_PLT;
-
- ret = wl12xx_chip_wakeup(wl);
+ /* FIXME: replace the magic numbers with proper definitions */
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
- return ret;
+ goto out_sleep;
- ret = wl->chip.op_boot(wl);
- if (ret < 0)
- return ret;
-
- wl12xx_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver);
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
- ret = wl->chip.op_plt_init(wl);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-int wl12xx_plt_stop(struct wl12xx *wl)
-{
- wl12xx_notice("power down");
-
- if (wl->state != WL12XX_STATE_PLT) {
- wl12xx_error("cannot power down because not in PLT "
- "state: %d", wl->state);
- return -EBUSY;
- }
-
- wl12xx_disable_interrupts(wl);
- wl12xx_power_off(wl);
-
- wl->state = WL12XX_STATE_OFF;
-
- return 0;
+out:
+ mutex_unlock(&wl->mutex);
}
-
-static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
skb_queue_tail(&wl->tx_queue, skb);
+ /*
+ * The chip specific setup must run before the first TX packet -
+ * before that, the tx_work will not be initialized!
+ */
+
schedule_work(&wl->tx_work);
/*
* The workqueue is slow to process the tx_queue and we need stop
* the queue here, otherwise the queue will get too long.
*/
- if (skb_queue_len(&wl->tx_queue) >= WL12XX_TX_QUEUE_MAX_LENGTH) {
+ if (skb_queue_len(&wl->tx_queue) >= WL1251_TX_QUEUE_MAX_LENGTH) {
ieee80211_stop_queues(wl->hw);
/*
@@ -318,25 +277,25 @@ static int wl12xx_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return NETDEV_TX_OK;
}
-static int wl12xx_op_start(struct ieee80211_hw *hw)
+static int wl1251_op_start(struct ieee80211_hw *hw)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 start");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 start");
mutex_lock(&wl->mutex);
- if (wl->state != WL12XX_STATE_OFF) {
- wl12xx_error("cannot start because not in off state: %d",
+ if (wl->state != WL1251_STATE_OFF) {
+ wl1251_error("cannot start because not in off state: %d",
wl->state);
ret = -EBUSY;
goto out;
}
- ret = wl12xx_chip_wakeup(wl);
+ ret = wl1251_chip_wakeup(wl);
if (ret < 0)
- return ret;
+ goto out;
ret = wl->chip.op_boot(wl);
if (ret < 0)
@@ -346,34 +305,34 @@ static int wl12xx_op_start(struct ieee80211_hw *hw)
if (ret < 0)
goto out;
- ret = wl12xx_acx_station_id(wl);
+ ret = wl1251_acx_station_id(wl);
if (ret < 0)
goto out;
- wl->state = WL12XX_STATE_ON;
+ wl->state = WL1251_STATE_ON;
- wl12xx_info("firmware booted (%s)", wl->chip.fw_ver);
+ wl1251_info("firmware booted (%s)", wl->chip.fw_ver);
out:
if (ret < 0)
- wl12xx_power_off(wl);
+ wl1251_power_off(wl);
mutex_unlock(&wl->mutex);
return ret;
}
-static void wl12xx_op_stop(struct ieee80211_hw *hw)
+static void wl1251_op_stop(struct ieee80211_hw *hw)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
- wl12xx_info("down");
+ wl1251_info("down");
- wl12xx_debug(DEBUG_MAC80211, "mac80211 stop");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 stop");
mutex_lock(&wl->mutex);
- WARN_ON(wl->state != WL12XX_STATE_ON);
+ WARN_ON(wl->state != WL1251_STATE_ON);
if (wl->scanning) {
mutex_unlock(&wl->mutex);
@@ -382,9 +341,9 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
wl->scanning = false;
}
- wl->state = WL12XX_STATE_OFF;
+ wl->state = WL1251_STATE_OFF;
- wl12xx_disable_interrupts(wl);
+ wl1251_disable_interrupts(wl);
mutex_unlock(&wl->mutex);
@@ -395,9 +354,8 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl12xx_tx_flush(wl);
-
- wl12xx_power_off(wl);
+ wl->chip.op_tx_flush(wl);
+ wl1251_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
wl->listen_int = 1;
@@ -412,22 +370,21 @@ static void wl12xx_op_stop(struct ieee80211_hw *hw)
wl->elp = false;
wl->psm = 0;
wl->tx_queue_stopped = false;
- wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
- wl12xx_debugfs_reset(wl);
+ wl1251_debugfs_reset(wl);
mutex_unlock(&wl->mutex);
}
-static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
+static int wl1251_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- struct wl12xx *wl = hw->priv;
- DECLARE_MAC_BUF(mac);
+ struct wl1251 *wl = hw->priv;
int ret = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
- conf->type, print_mac(mac, conf->mac_addr));
+ wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+ conf->type, conf->mac_addr);
mutex_lock(&wl->mutex);
@@ -446,7 +403,7 @@ static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) {
memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr);
- ret = wl12xx_acx_station_id(wl);
+ ret = wl1251_acx_station_id(wl);
if (ret < 0)
goto out;
}
@@ -456,13 +413,13 @@ out:
return ret;
}
-static void wl12xx_op_remove_interface(struct ieee80211_hw *hw,
+static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf)
{
- wl12xx_debug(DEBUG_MAC80211, "mac80211 remove interface");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
}
-static int wl12xx_build_null_data(struct wl12xx *wl)
+static int wl1251_build_null_data(struct wl1251 *wl)
{
struct wl12xx_null_data_template template;
@@ -478,12 +435,12 @@ static int wl12xx_build_null_data(struct wl12xx *wl)
template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC);
- return wl12xx_cmd_template_set(wl, CMD_NULL_DATA, &template,
+ return wl1251_cmd_template_set(wl, CMD_NULL_DATA, &template,
sizeof(template));
}
-static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
+static int wl1251_build_ps_poll(struct wl1251 *wl, u16 aid)
{
struct wl12xx_ps_poll_template template;
@@ -492,41 +449,45 @@ static int wl12xx_build_ps_poll(struct wl12xx *wl, u16 aid)
template.aid = aid;
template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
- return wl12xx_cmd_template_set(wl, CMD_PS_POLL, &template,
+ return wl1251_cmd_template_set(wl, CMD_PS_POLL, &template,
sizeof(template));
}
-static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
+static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
int channel, ret = 0;
channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
- wl12xx_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+ wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
channel,
conf->flags & IEEE80211_CONF_PS ? "on" : "off",
conf->power_level);
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (channel != wl->channel) {
/* FIXME: use beacon interval provided by mac80211 */
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
- goto out;
+ goto out_sleep;
wl->channel = channel;
}
- ret = wl12xx_build_null_data(wl);
+ ret = wl1251_build_null_data(wl);
if (ret < 0)
- goto out;
+ goto out_sleep;
if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
- wl12xx_info("psm enabled");
+ wl1251_debug(DEBUG_PSM, "psm enabled");
wl->psm_requested = true;
@@ -535,49 +496,53 @@ static int wl12xx_op_config(struct ieee80211_hw *hw, u32 changed)
* If we're not, we'll enter it when joining an SSID,
* through the bss_info_changed() hook.
*/
- ret = wl12xx_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
} else if (!(conf->flags & IEEE80211_CONF_PS) &&
wl->psm_requested) {
- wl12xx_info("psm disabled");
+ wl1251_debug(DEBUG_PSM, "psm disabled");
wl->psm_requested = false;
if (wl->psm)
- ret = wl12xx_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
}
if (conf->power_level != wl->power_level) {
- ret = wl12xx_acx_tx_power(wl, conf->power_level);
+ ret = wl1251_acx_tx_power(wl, conf->power_level);
if (ret < 0)
goto out;
wl->power_level = conf->power_level;
}
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
+
return ret;
}
-#define WL12XX_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
+#define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
FIF_FCSFAIL | \
FIF_BCN_PRBRESP_PROMISC | \
FIF_CONTROL | \
FIF_OTHER_BSS)
-static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
+static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed,
unsigned int *total,
int mc_count,
struct dev_addr_list *mc_list)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 configure filter");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter");
- *total &= WL12XX_SUPPORTED_FILTERS;
- changed &= WL12XX_SUPPORTED_FILTERS;
+ *total &= WL1251_SUPPORTED_FILTERS;
+ changed &= WL1251_SUPPORTED_FILTERS;
if (changed == 0)
/* no filters which we support changed */
@@ -585,8 +550,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
/* FIXME: wl->rx_config and wl->rx_filter are not protected */
- wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
if (*total & FIF_PROMISC_IN_BSS) {
wl->rx_config |= CFG_BSSID_FILTER_EN;
@@ -618,7 +583,8 @@ static void wl12xx_op_configure_filter(struct ieee80211_hw *hw,
}
/* HW encryption */
-static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
+static int wl1251_set_key_type(struct wl1251 *wl,
+ struct wl1251_cmd_set_keys *key,
enum set_key_cmd cmd,
struct ieee80211_key_conf *mac80211_key,
const u8 *addr)
@@ -648,95 +614,116 @@ static int wl12xx_set_key_type(struct wl12xx *wl, struct acx_set_key *key,
mac80211_key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
break;
default:
- wl12xx_error("Unknown key algo 0x%x", mac80211_key->alg);
+ wl1251_error("Unknown key algo 0x%x", mac80211_key->alg);
return -EOPNOTSUPP;
}
return 0;
}
-static int wl12xx_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
- struct wl12xx *wl = hw->priv;
- struct acx_set_key wl_key;
+ struct wl1251 *wl = hw->priv;
+ struct wl1251_cmd_set_keys *wl_cmd;
const u8 *addr;
int ret;
static const u8 bcast_addr[ETH_ALEN] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- wl12xx_debug(DEBUG_MAC80211, "mac80211 set key");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 set key");
- memset(&wl_key, 0, sizeof(wl_key));
+ wl_cmd = kzalloc(sizeof(*wl_cmd), GFP_KERNEL);
+ if (!wl_cmd) {
+ ret = -ENOMEM;
+ goto out;
+ }
addr = sta ? sta->addr : bcast_addr;
- wl12xx_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
- wl12xx_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
- wl12xx_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
+ wl1251_debug(DEBUG_CRYPT, "CMD: 0x%x", cmd);
+ wl1251_dump(DEBUG_CRYPT, "ADDR: ", addr, ETH_ALEN);
+ wl1251_debug(DEBUG_CRYPT, "Key: algo:0x%x, id:%d, len:%d flags 0x%x",
key->alg, key->keyidx, key->keylen, key->flags);
- wl12xx_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+ wl1251_dump(DEBUG_CRYPT, "KEY: ", key->key, key->keylen);
+
+ if (is_zero_ether_addr(addr)) {
+ /* We dont support TX only encryption */
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_unlock;
+
switch (cmd) {
case SET_KEY:
- wl_key.key_action = KEY_ADD_OR_REPLACE;
+ wl_cmd->key_action = KEY_ADD_OR_REPLACE;
break;
case DISABLE_KEY:
- wl_key.key_action = KEY_REMOVE;
+ wl_cmd->key_action = KEY_REMOVE;
break;
default:
- wl12xx_error("Unsupported key cmd 0x%x", cmd);
+ wl1251_error("Unsupported key cmd 0x%x", cmd);
break;
}
- ret = wl12xx_set_key_type(wl, &wl_key, cmd, key, addr);
+ ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
if (ret < 0) {
- wl12xx_error("Set KEY type failed");
- goto out;
+ wl1251_error("Set KEY type failed");
+ goto out_sleep;
}
- if (wl_key.key_type != KEY_WEP_DEFAULT)
- memcpy(wl_key.addr, addr, ETH_ALEN);
+ if (wl_cmd->key_type != KEY_WEP_DEFAULT)
+ memcpy(wl_cmd->addr, addr, ETH_ALEN);
- if ((wl_key.key_type == KEY_TKIP_MIC_GROUP) ||
- (wl_key.key_type == KEY_TKIP_MIC_PAIRWISE)) {
+ if ((wl_cmd->key_type == KEY_TKIP_MIC_GROUP) ||
+ (wl_cmd->key_type == KEY_TKIP_MIC_PAIRWISE)) {
/*
* We get the key in the following form:
* TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
* but the target is expecting:
* TKIP - RX MIC - TX MIC
*/
- memcpy(wl_key.key, key->key, 16);
- memcpy(wl_key.key + 16, key->key + 24, 8);
- memcpy(wl_key.key + 24, key->key + 16, 8);
+ memcpy(wl_cmd->key, key->key, 16);
+ memcpy(wl_cmd->key + 16, key->key + 24, 8);
+ memcpy(wl_cmd->key + 24, key->key + 16, 8);
} else {
- memcpy(wl_key.key, key->key, key->keylen);
+ memcpy(wl_cmd->key, key->key, key->keylen);
}
- wl_key.key_size = key->keylen;
+ wl_cmd->key_size = key->keylen;
- wl_key.id = key->keyidx;
- wl_key.ssid_profile = 0;
+ wl_cmd->id = key->keyidx;
+ wl_cmd->ssid_profile = 0;
- wl12xx_dump(DEBUG_CRYPT, "TARGET KEY: ", &wl_key, sizeof(wl_key));
+ wl1251_dump(DEBUG_CRYPT, "TARGET KEY: ", wl_cmd, sizeof(*wl_cmd));
- if (wl12xx_cmd_send(wl, CMD_SET_KEYS, &wl_key, sizeof(wl_key)) < 0) {
- wl12xx_error("Set KEY failed");
- ret = -EOPNOTSUPP;
- goto out;
+ ret = wl1251_cmd_send(wl, CMD_SET_KEYS, wl_cmd, sizeof(*wl_cmd));
+ if (ret < 0) {
+ wl1251_warning("could not set keys");
+ goto out_sleep;
}
-out:
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
+out_unlock:
mutex_unlock(&wl->mutex);
+
+out:
+ kfree(wl_cmd);
+
return ret;
}
-static int wl12xx_build_basic_rates(char *rates)
+static int wl1251_build_basic_rates(char *rates)
{
u8 index = 0;
@@ -748,7 +735,7 @@ static int wl12xx_build_basic_rates(char *rates)
return index;
}
-static int wl12xx_build_extended_rates(char *rates)
+static int wl1251_build_extended_rates(char *rates)
{
u8 index = 0;
@@ -765,7 +752,7 @@ static int wl12xx_build_extended_rates(char *rates)
}
-static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
+static int wl1251_build_probe_req(struct wl1251 *wl, u8 *ssid, size_t ssid_len)
{
struct wl12xx_probe_req_template template;
struct wl12xx_ie_rates *rates;
@@ -792,31 +779,30 @@ static int wl12xx_build_probe_req(struct wl12xx *wl, u8 *ssid, size_t ssid_len)
/* Basic Rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_SUPP_RATES;
- rates->header.len = wl12xx_build_basic_rates(rates->rates);
+ rates->header.len = wl1251_build_basic_rates(rates->rates);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
ptr += sizeof(struct wl12xx_ie_header) + rates->header.len;
/* Extended rates */
rates = (struct wl12xx_ie_rates *)ptr;
rates->header.id = WLAN_EID_EXT_SUPP_RATES;
- rates->header.len = wl12xx_build_extended_rates(rates->rates);
+ rates->header.len = wl1251_build_extended_rates(rates->rates);
size += sizeof(struct wl12xx_ie_header) + rates->header.len;
- wl12xx_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
+ wl1251_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size);
- return wl12xx_cmd_template_set(wl, CMD_PROBE_REQ, &template,
+ return wl1251_cmd_template_set(wl, CMD_PROBE_REQ, &template,
size);
}
-static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
+static int wl1251_hw_scan(struct wl1251 *wl, u8 *ssid, size_t len,
u8 active_scan, u8 high_prio, u8 num_channels,
u8 probe_requests)
{
+ struct wl1251_cmd_trigger_scan_to *trigger = NULL;
+ struct cmd_scan *params = NULL;
int i, ret;
- u32 split_scan = 0;
u16 scan_options = 0;
- struct cmd_scan *params;
- struct wl12xx_command *cmd_answer;
if (wl->scanning)
return -EINVAL;
@@ -864,33 +850,38 @@ static int wl12xx_hw_scan(struct wl12xx *wl, u8 *ssid, size_t len,
memset(params->params.ssid, 0, 32);
}
- ret = wl12xx_build_probe_req(wl, ssid, len);
+ ret = wl1251_build_probe_req(wl, ssid, len);
if (ret < 0) {
- wl12xx_error("PROBE request template failed");
+ wl1251_error("PROBE request template failed");
goto out;
}
- ret = wl12xx_cmd_send(wl, CMD_TRIGGER_SCAN_TO, &split_scan,
- sizeof(u32));
+ trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
+ if (!trigger)
+ goto out;
+
+ trigger->timeout = 0;
+
+ ret = wl1251_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger,
+ sizeof(*trigger));
if (ret < 0) {
- wl12xx_error("Split SCAN failed");
+ wl1251_error("trigger scan to failed for hw scan");
goto out;
}
- wl12xx_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
+ wl1251_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params));
wl->scanning = true;
- ret = wl12xx_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
+ ret = wl1251_cmd_send(wl, CMD_SCAN, params, sizeof(*params));
if (ret < 0)
- wl12xx_error("SCAN failed");
+ wl1251_error("SCAN failed");
- wl12xx_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
+ wl1251_spi_mem_read(wl, wl->cmd_box_addr, params, sizeof(*params));
- cmd_answer = (struct wl12xx_command *) params;
- if (cmd_answer->status != CMD_STATUS_SUCCESS) {
- wl12xx_error("TEST command answer error: %d",
- cmd_answer->status);
+ if (params->header.status != CMD_STATUS_SUCCESS) {
+ wl1251_error("TEST command answer error: %d",
+ params->header.status);
wl->scanning = false;
ret = -EIO;
goto out;
@@ -902,15 +893,15 @@ out:
}
-static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
+static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
struct cfg80211_scan_request *req)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret;
u8 *ssid = NULL;
size_t ssid_len = 0;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 hw scan");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 hw scan");
if (req->n_ssids) {
ssid = req->ssids[0].ssid;
@@ -918,85 +909,108 @@ static int wl12xx_op_hw_scan(struct ieee80211_hw *hw,
}
mutex_lock(&wl->mutex);
- ret = wl12xx_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1251_hw_scan(hw->priv, ssid, ssid_len, 1, 0, 13, 3);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
mutex_unlock(&wl->mutex);
return ret;
}
-static int wl12xx_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
{
- struct wl12xx *wl = hw->priv;
+ struct wl1251 *wl = hw->priv;
int ret;
- ret = wl12xx_acx_rts_threshold(wl, (u16) value);
+ mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
if (ret < 0)
- wl12xx_warning("wl12xx_op_set_rts_threshold failed: %d", ret);
+ goto out;
+
+ ret = wl1251_acx_rts_threshold(wl, (u16) value);
+ if (ret < 0)
+ wl1251_warning("wl1251_op_set_rts_threshold failed: %d", ret);
+
+ wl1251_ps_elp_sleep(wl);
+
+out:
+ mutex_unlock(&wl->mutex);
return ret;
}
-static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
+static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
u32 changed)
{
- enum acx_ps_mode mode;
- struct wl12xx *wl = hw->priv;
+ enum wl1251_cmd_ps_mode mode;
+ struct wl1251 *wl = hw->priv;
struct sk_buff *beacon;
int ret;
- wl12xx_debug(DEBUG_MAC80211, "mac80211 bss info changed");
+ wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
mutex_lock(&wl->mutex);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
wl->aid = bss_conf->aid;
- ret = wl12xx_build_ps_poll(wl, wl->aid);
+ ret = wl1251_build_ps_poll(wl, wl->aid);
if (ret < 0)
- goto out;
+ goto out_sleep;
- ret = wl12xx_acx_aid(wl, wl->aid);
+ ret = wl1251_acx_aid(wl, wl->aid);
if (ret < 0)
- goto out;
+ goto out_sleep;
/* If we want to go in PSM but we're not there yet */
if (wl->psm_requested && !wl->psm) {
mode = STATION_POWER_SAVE_MODE;
- ret = wl12xx_ps_set_mode(wl, mode);
+ ret = wl1251_ps_set_mode(wl, mode);
if (ret < 0)
- goto out;
+ goto out_sleep;
}
}
}
if (changed & BSS_CHANGED_ERP_SLOT) {
if (bss_conf->use_short_slot)
- ret = wl12xx_acx_slot(wl, SLOT_TIME_SHORT);
+ ret = wl1251_acx_slot(wl, SLOT_TIME_SHORT);
else
- ret = wl12xx_acx_slot(wl, SLOT_TIME_LONG);
+ ret = wl1251_acx_slot(wl, SLOT_TIME_LONG);
if (ret < 0) {
- wl12xx_warning("Set slot time failed %d", ret);
- goto out;
+ wl1251_warning("Set slot time failed %d", ret);
+ goto out_sleep;
}
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
if (bss_conf->use_short_preamble)
- wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
+ wl1251_acx_set_preamble(wl, ACX_PREAMBLE_SHORT);
else
- wl12xx_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
+ wl1251_acx_set_preamble(wl, ACX_PREAMBLE_LONG);
}
if (changed & BSS_CHANGED_ERP_CTS_PROT) {
if (bss_conf->use_cts_prot)
- ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_ENABLE);
+ ret = wl1251_acx_cts_protect(wl, CTSPROTECT_ENABLE);
else
- ret = wl12xx_acx_cts_protect(wl, CTSPROTECT_DISABLE);
+ ret = wl1251_acx_cts_protect(wl, CTSPROTECT_DISABLE);
if (ret < 0) {
- wl12xx_warning("Set ctsprotect failed %d", ret);
+ wl1251_warning("Set ctsprotect failed %d", ret);
goto out;
}
}
@@ -1004,20 +1018,22 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID) {
memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN);
- ret = wl12xx_build_null_data(wl);
+ ret = wl1251_build_null_data(wl);
if (ret < 0)
goto out;
if (wl->bss_type != BSS_TYPE_IBSS) {
- ret = wl12xx_cmd_join(wl, wl->bss_type, 5, 100, 1);
+ ret = wl1251_cmd_join(wl, wl->bss_type, 5, 100, 1);
if (ret < 0)
- goto out;
+ goto out_sleep;
+ wl1251_warning("Set ctsprotect failed %d", ret);
+ goto out_sleep;
}
}
if (changed & BSS_CHANGED_BEACON) {
beacon = ieee80211_beacon_get(hw, vif);
- ret = wl12xx_cmd_template_set(wl, CMD_BEACON, beacon->data,
+ ret = wl1251_cmd_template_set(wl, CMD_BEACON, beacon->data,
beacon->len);
if (ret < 0) {
@@ -1025,7 +1041,7 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
goto out;
}
- ret = wl12xx_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
+ ret = wl1251_cmd_template_set(wl, CMD_PROBE_RESP, beacon->data,
beacon->len);
dev_kfree_skb(beacon);
@@ -1033,19 +1049,22 @@ static void wl12xx_op_bss_info_changed(struct ieee80211_hw *hw,
if (ret < 0)
goto out;
- ret = wl12xx_cmd_join(wl, wl->bss_type, 1, 100, 0);
+ ret = wl->chip.op_cmd_join(wl, wl->bss_type, 1, 100, 0);
if (ret < 0)
goto out;
}
+out_sleep:
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
}
/* can't be const, mac80211 writes to this */
-static struct ieee80211_rate wl12xx_rates[] = {
+static struct ieee80211_rate wl1251_rates[] = {
{ .bitrate = 10,
.hw_value = 0x1,
.hw_value_short = 0x1, },
@@ -1088,7 +1107,7 @@ static struct ieee80211_rate wl12xx_rates[] = {
};
/* can't be const, mac80211 writes to this */
-static struct ieee80211_channel wl12xx_channels[] = {
+static struct ieee80211_channel wl1251_channels[] = {
{ .hw_value = 1, .center_freq = 2412},
{ .hw_value = 2, .center_freq = 2417},
{ .hw_value = 3, .center_freq = 2422},
@@ -1105,28 +1124,28 @@ static struct ieee80211_channel wl12xx_channels[] = {
};
/* can't be const, mac80211 writes to this */
-static struct ieee80211_supported_band wl12xx_band_2ghz = {
- .channels = wl12xx_channels,
- .n_channels = ARRAY_SIZE(wl12xx_channels),
- .bitrates = wl12xx_rates,
- .n_bitrates = ARRAY_SIZE(wl12xx_rates),
+static struct ieee80211_supported_band wl1251_band_2ghz = {
+ .channels = wl1251_channels,
+ .n_channels = ARRAY_SIZE(wl1251_channels),
+ .bitrates = wl1251_rates,
+ .n_bitrates = ARRAY_SIZE(wl1251_rates),
};
-static const struct ieee80211_ops wl12xx_ops = {
- .start = wl12xx_op_start,
- .stop = wl12xx_op_stop,
- .add_interface = wl12xx_op_add_interface,
- .remove_interface = wl12xx_op_remove_interface,
- .config = wl12xx_op_config,
- .configure_filter = wl12xx_op_configure_filter,
- .tx = wl12xx_op_tx,
- .set_key = wl12xx_op_set_key,
- .hw_scan = wl12xx_op_hw_scan,
- .bss_info_changed = wl12xx_op_bss_info_changed,
- .set_rts_threshold = wl12xx_op_set_rts_threshold,
+static const struct ieee80211_ops wl1251_ops = {
+ .start = wl1251_op_start,
+ .stop = wl1251_op_stop,
+ .add_interface = wl1251_op_add_interface,
+ .remove_interface = wl1251_op_remove_interface,
+ .config = wl1251_op_config,
+ .configure_filter = wl1251_op_configure_filter,
+ .tx = wl1251_op_tx,
+ .set_key = wl1251_op_set_key,
+ .hw_scan = wl1251_op_hw_scan,
+ .bss_info_changed = wl1251_op_bss_info_changed,
+ .set_rts_threshold = wl1251_op_set_rts_threshold,
};
-static int wl12xx_register_hw(struct wl12xx *wl)
+static int wl1251_register_hw(struct wl1251 *wl)
{
int ret;
@@ -1137,22 +1156,22 @@ static int wl12xx_register_hw(struct wl12xx *wl)
ret = ieee80211_register_hw(wl->hw);
if (ret < 0) {
- wl12xx_error("unable to register mac80211 hw: %d", ret);
+ wl1251_error("unable to register mac80211 hw: %d", ret);
return ret;
}
wl->mac80211_registered = true;
- wl12xx_notice("loaded");
+ wl1251_notice("loaded");
return 0;
}
-static int wl12xx_init_ieee80211(struct wl12xx *wl)
+static int wl1251_init_ieee80211(struct wl1251 *wl)
{
/* The tx descriptor buffer and the TKIP space */
wl->hw->extra_tx_headroom = sizeof(struct tx_double_buffer_desc)
- + WL12XX_TKIP_IV_SPACE;
+ + WL1251_TKIP_IV_SPACE;
/* unit us */
/* FIXME: find a proper value */
@@ -1163,31 +1182,31 @@ static int wl12xx_init_ieee80211(struct wl12xx *wl)
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
wl->hw->wiphy->max_scan_ssids = 1;
- wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl12xx_band_2ghz;
+ wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1251_band_2ghz;
SET_IEEE80211_DEV(wl->hw, &wl->spi->dev);
return 0;
}
-#define WL12XX_DEFAULT_CHANNEL 1
-static int __devinit wl12xx_probe(struct spi_device *spi)
+#define WL1251_DEFAULT_CHANNEL 1
+static int __devinit wl1251_probe(struct spi_device *spi)
{
struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
- struct wl12xx *wl;
+ struct wl1251 *wl;
int ret, i;
static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
pdata = spi->dev.platform_data;
if (!pdata) {
- wl12xx_error("no platform data");
+ wl1251_error("no platform data");
return -ENODEV;
}
- hw = ieee80211_alloc_hw(sizeof(*wl), &wl12xx_ops);
+ hw = ieee80211_alloc_hw(sizeof(*wl), &wl1251_ops);
if (!hw) {
- wl12xx_error("could not alloc ieee80211_hw");
+ wl1251_error("could not alloc ieee80211_hw");
return -ENOMEM;
}
@@ -1202,9 +1221,8 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
skb_queue_head_init(&wl->tx_queue);
- INIT_WORK(&wl->tx_work, wl12xx_tx_work);
- INIT_WORK(&wl->filter_work, wl12xx_filter_work);
- wl->channel = WL12XX_DEFAULT_CHANNEL;
+ INIT_WORK(&wl->filter_work, wl1251_filter_work);
+ wl->channel = WL1251_DEFAULT_CHANNEL;
wl->scanning = false;
wl->default_key = 0;
wl->listen_int = 1;
@@ -1212,17 +1230,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
wl->rx_handled = 0;
wl->rx_current_buffer = 0;
wl->rx_last_id = 0;
- wl->rx_config = WL12XX_DEFAULT_RX_CONFIG;
- wl->rx_filter = WL12XX_DEFAULT_RX_FILTER;
+ wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
+ wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
wl->elp = false;
wl->psm = 0;
wl->psm_requested = false;
wl->tx_queue_stopped = false;
- wl->power_level = WL12XX_DEFAULT_POWER_LEVEL;
+ wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
/* We use the default power on sleep time until we know which chip
* we're using */
- wl->chip.power_on_sleep = WL12XX_DEFAULT_POWER_ON_SLEEP;
+ wl->chip.power_on_sleep = WL1251_DEFAULT_POWER_ON_SLEEP;
for (i = 0; i < FW_TX_CMPLT_BLOCK_SIZE; i++)
wl->tx_frames[i] = NULL;
@@ -1236,37 +1254,46 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
memcpy(wl->mac_addr, nokia_oui, 3);
get_random_bytes(wl->mac_addr + 3, 3);
- wl->state = WL12XX_STATE_OFF;
+ wl->state = WL1251_STATE_OFF;
mutex_init(&wl->mutex);
wl->tx_mgmt_frm_rate = DEFAULT_HW_GEN_TX_RATE;
wl->tx_mgmt_frm_mod = DEFAULT_HW_GEN_MODULATION_TYPE;
+ wl->rx_descriptor = kmalloc(sizeof(*wl->rx_descriptor), GFP_KERNEL);
+ if (!wl->rx_descriptor) {
+ wl1251_error("could not allocate memory for rx descriptor");
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
/* This is the only SPI value that we need to set here, the rest
* comes from the board-peripherals file */
spi->bits_per_word = 32;
ret = spi_setup(spi);
if (ret < 0) {
- wl12xx_error("spi_setup failed");
+ wl1251_error("spi_setup failed");
goto out_free;
}
wl->set_power = pdata->set_power;
if (!wl->set_power) {
- wl12xx_error("set power function missing in platform data");
- return -ENODEV;
+ wl1251_error("set power function missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
}
wl->irq = spi->irq;
if (wl->irq < 0) {
- wl12xx_error("irq missing in platform data");
- return -ENODEV;
+ wl1251_error("irq missing in platform data");
+ ret = -ENODEV;
+ goto out_free;
}
- ret = request_irq(wl->irq, wl12xx_irq, 0, DRIVER_NAME, wl);
+ ret = request_irq(wl->irq, wl1251_irq, 0, DRIVER_NAME, wl);
if (ret < 0) {
- wl12xx_error("request_irq() failed: %d", ret);
+ wl1251_error("request_irq() failed: %d", ret);
goto out_free;
}
@@ -1274,17 +1301,17 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
disable_irq(wl->irq);
- ret = wl12xx_init_ieee80211(wl);
+ ret = wl1251_init_ieee80211(wl);
if (ret)
goto out_irq;
- ret = wl12xx_register_hw(wl);
+ ret = wl1251_register_hw(wl);
if (ret)
goto out_irq;
- wl12xx_debugfs_init(wl);
+ wl1251_debugfs_init(wl);
- wl12xx_notice("initialized");
+ wl1251_notice("initialized");
return 0;
@@ -1292,18 +1319,21 @@ static int __devinit wl12xx_probe(struct spi_device *spi)
free_irq(wl->irq, wl);
out_free:
+ kfree(wl->rx_descriptor);
+ wl->rx_descriptor = NULL;
+
ieee80211_free_hw(hw);
return ret;
}
-static int __devexit wl12xx_remove(struct spi_device *spi)
+static int __devexit wl1251_remove(struct spi_device *spi)
{
- struct wl12xx *wl = dev_get_drvdata(&spi->dev);
+ struct wl1251 *wl = dev_get_drvdata(&spi->dev);
ieee80211_unregister_hw(wl->hw);
- wl12xx_debugfs_exit(wl);
+ wl1251_debugfs_exit(wl);
free_irq(wl->irq, wl);
kfree(wl->target_mem_map);
@@ -1312,30 +1342,35 @@ static int __devexit wl12xx_remove(struct spi_device *spi)
wl->fw = NULL;
kfree(wl->nvs);
wl->nvs = NULL;
+
+ kfree(wl->rx_descriptor);
+ wl->rx_descriptor = NULL;
+
ieee80211_free_hw(wl->hw);
return 0;
}
-static struct spi_driver wl12xx_spi_driver = {
+static struct spi_driver wl1251_spi_driver = {
.driver = {
+ /* FIXME: use wl12xx name to not break the user space */
.name = "wl12xx",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
- .probe = wl12xx_probe,
- .remove = __devexit_p(wl12xx_remove),
+ .probe = wl1251_probe,
+ .remove = __devexit_p(wl1251_remove),
};
-static int __init wl12xx_init(void)
+static int __init wl1251_init(void)
{
int ret;
- ret = spi_register_driver(&wl12xx_spi_driver);
+ ret = spi_register_driver(&wl1251_spi_driver);
if (ret < 0) {
- wl12xx_error("failed to register spi driver: %d", ret);
+ wl1251_error("failed to register spi driver: %d", ret);
goto out;
}
@@ -1343,15 +1378,15 @@ out:
return ret;
}
-static void __exit wl12xx_exit(void)
+static void __exit wl1251_exit(void)
{
- spi_unregister_driver(&wl12xx_spi_driver);
+ spi_unregister_driver(&wl1251_spi_driver);
- wl12xx_notice("unloaded");
+ wl1251_notice("unloaded");
}
-module_init(wl12xx_init);
-module_exit(wl12xx_exit);
+module_init(wl1251_init);
+module_exit(wl1251_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kalle Valo <Kalle.Valo@nokia.com>, "
diff --git a/drivers/net/wireless/wl12xx/wl1251_netlink.h b/drivers/net/wireless/wl12xx/wl1251_netlink.h
new file mode 100644
index 00000000000..ee36695e134
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_netlink.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1251_NETLINK_H__
+#define __WL1251_NETLINK_H__
+
+int wl1251_nl_register(void);
+void wl1251_nl_unregister(void);
+
+#endif /* __WL1251_NETLINK_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251.c b/drivers/net/wireless/wl12xx/wl1251_ops.c
index ce1561a41fa..e7b9aab3682 100644
--- a/drivers/net/wireless/wl12xx/wl1251.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ops.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008-2009 Nokia Corporation
*
@@ -24,18 +24,18 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "wl1251.h"
+#include "wl1251_ops.h"
#include "reg.h"
-#include "spi.h"
-#include "boot.h"
-#include "event.h"
-#include "acx.h"
-#include "tx.h"
-#include "rx.h"
-#include "ps.h"
-#include "init.h"
-
-static struct wl12xx_partition_set wl1251_part_table[PART_TABLE_LEN] = {
+#include "wl1251_spi.h"
+#include "wl1251_boot.h"
+#include "wl1251_event.h"
+#include "wl1251_acx.h"
+#include "wl1251_tx.h"
+#include "wl1251_rx.h"
+#include "wl1251_ps.h"
+#include "wl1251_init.h"
+
+static struct wl1251_partition_set wl1251_part_table[PART_TABLE_LEN] = {
[PART_DOWN] = {
.mem = {
.start = 0x00000000,
@@ -75,31 +75,31 @@ static enum wl12xx_acx_int_reg wl1251_acx_reg_table[ACX_REG_TABLE_LEN] = {
[ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804)
};
-static int wl1251_upload_firmware(struct wl12xx *wl)
+static int wl1251_upload_firmware(struct wl1251 *wl)
{
- struct wl12xx_partition_set *p_table = wl->chip.p_table;
+ struct wl1251_partition_set *p_table = wl->chip.p_table;
int addr, chunk_num, partition_limit;
size_t fw_data_len;
u8 *p;
/* whal_FwCtrl_LoadFwImageSm() */
- wl12xx_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
- wl12xx_reg_read32(wl, CHIP_ID_B));
+ wl1251_debug(DEBUG_BOOT, "chip id before fw upload: 0x%x",
+ wl1251_reg_read32(wl, CHIP_ID_B));
/* 10.0 check firmware length and set partition */
fw_data_len = (wl->fw[4] << 24) | (wl->fw[5] << 16) |
(wl->fw[6] << 8) | (wl->fw[7]);
- wl12xx_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
+ wl1251_debug(DEBUG_BOOT, "fw_data_len %zu chunk_size %d", fw_data_len,
CHUNK_SIZE);
if ((fw_data_len % 4) != 0) {
- wl12xx_error("firmware length not multiple of four");
+ wl1251_error("firmware length not multiple of four");
return -EIO;
}
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
p_table[PART_DOWN].mem.start,
p_table[PART_DOWN].mem.size,
p_table[PART_DOWN].reg.start,
@@ -118,7 +118,7 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
chunk_num * CHUNK_SIZE;
partition_limit = chunk_num * CHUNK_SIZE +
p_table[PART_DOWN].mem.size;
- wl12xx_set_partition(wl,
+ wl1251_set_partition(wl,
addr,
p_table[PART_DOWN].mem.size,
p_table[PART_DOWN].reg.start,
@@ -128,9 +128,9 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
/* 10.3 upload the chunk */
addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
- wl12xx_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
+ wl1251_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x",
p, addr);
- wl12xx_spi_mem_write(wl, addr, p, CHUNK_SIZE);
+ wl1251_spi_mem_write(wl, addr, p, CHUNK_SIZE);
chunk_num++;
}
@@ -138,14 +138,14 @@ static int wl1251_upload_firmware(struct wl12xx *wl)
/* 10.4 upload the last chunk */
addr = p_table[PART_DOWN].mem.start + chunk_num * CHUNK_SIZE;
p = wl->fw + FW_HDR_SIZE + chunk_num * CHUNK_SIZE;
- wl12xx_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
+ wl1251_debug(DEBUG_BOOT, "uploading fw last chunk (%zu B) 0x%p to 0x%x",
fw_data_len % CHUNK_SIZE, p, addr);
- wl12xx_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
+ wl1251_spi_mem_write(wl, addr, p, fw_data_len % CHUNK_SIZE);
return 0;
}
-static int wl1251_upload_nvs(struct wl12xx *wl)
+static int wl1251_upload_nvs(struct wl1251 *wl)
{
size_t nvs_len, nvs_bytes_written, burst_len;
int nvs_start, i;
@@ -181,10 +181,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
val = (nvs_ptr[0] | (nvs_ptr[1] << 8)
| (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24));
- wl12xx_debug(DEBUG_BOOT,
+ wl1251_debug(DEBUG_BOOT,
"nvs burst write 0x%x: 0x%x",
dest_addr, val);
- wl12xx_mem_write32(wl, dest_addr, val);
+ wl1251_mem_write32(wl, dest_addr, val);
nvs_ptr += 4;
dest_addr += 4;
@@ -200,7 +200,7 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
nvs_len = ALIGN(nvs_len, 4);
/* Now we must set the partition correctly */
- wl12xx_set_partition(wl, nvs_start,
+ wl1251_set_partition(wl, nvs_start,
wl->chip.p_table[PART_DOWN].mem.size,
wl->chip.p_table[PART_DOWN].reg.start,
wl->chip.p_table[PART_DOWN].reg.size);
@@ -213,10 +213,10 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
val = cpu_to_le32(val);
- wl12xx_debug(DEBUG_BOOT,
+ wl1251_debug(DEBUG_BOOT,
"nvs write table 0x%x: 0x%x",
nvs_start, val);
- wl12xx_mem_write32(wl, nvs_start, val);
+ wl1251_mem_write32(wl, nvs_start, val);
nvs_ptr += 4;
nvs_bytes_written += 4;
@@ -226,12 +226,12 @@ static int wl1251_upload_nvs(struct wl12xx *wl)
return 0;
}
-static int wl1251_boot(struct wl12xx *wl)
+static int wl1251_boot(struct wl1251 *wl)
{
int ret = 0, minor_minor_e2_ver;
u32 tmp, boot_data;
- ret = wl12xx_boot_soft_reset(wl);
+ ret = wl1251_boot_soft_reset(wl);
if (ret < 0)
goto out;
@@ -242,39 +242,39 @@ static int wl1251_boot(struct wl12xx *wl)
/* write firmware's last address (ie. it's length) to
* ACX_EEPROMLESS_IND_REG */
- wl12xx_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
+ wl1251_reg_write32(wl, ACX_EEPROMLESS_IND_REG, wl->fw_len);
/* 6. read the EEPROM parameters */
- tmp = wl12xx_reg_read32(wl, SCR_PAD2);
+ tmp = wl1251_reg_read32(wl, SCR_PAD2);
/* 7. read bootdata */
wl->boot_attr.radio_type = (tmp & 0x0000FF00) >> 8;
wl->boot_attr.major = (tmp & 0x00FF0000) >> 16;
- tmp = wl12xx_reg_read32(wl, SCR_PAD3);
+ tmp = wl1251_reg_read32(wl, SCR_PAD3);
/* 8. check bootdata and call restart sequence */
wl->boot_attr.minor = (tmp & 0x00FF0000) >> 16;
minor_minor_e2_ver = (tmp & 0xFF000000) >> 24;
- wl12xx_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
+ wl1251_debug(DEBUG_BOOT, "radioType 0x%x majorE2Ver 0x%x "
"minorE2Ver 0x%x minor_minor_e2_ver 0x%x",
wl->boot_attr.radio_type, wl->boot_attr.major,
wl->boot_attr.minor, minor_minor_e2_ver);
- ret = wl12xx_boot_init_seq(wl);
+ ret = wl1251_boot_init_seq(wl);
if (ret < 0)
goto out;
/* 9. NVS processing done */
- boot_data = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+ boot_data = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
- wl12xx_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
+ wl1251_debug(DEBUG_BOOT, "halt boot_data 0x%x", boot_data);
/* 10. check that ECPU_CONTROL_HALT bits are set in
* pWhalBus->uBootData and start uploading firmware
*/
if ((boot_data & ECPU_CONTROL_HALT) == 0) {
- wl12xx_error("boot failed, ECPU_CONTROL_HALT not set");
+ wl1251_error("boot failed, ECPU_CONTROL_HALT not set");
ret = -EIO;
goto out;
}
@@ -284,62 +284,62 @@ static int wl1251_boot(struct wl12xx *wl)
goto out;
/* 10.5 start firmware */
- ret = wl12xx_boot_run_firmware(wl);
+ ret = wl1251_boot_run_firmware(wl);
if (ret < 0)
goto out;
- /* Get and save the firmware version */
- wl12xx_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
-
out:
return ret;
}
-static int wl1251_mem_cfg(struct wl12xx *wl)
+static int wl1251_mem_cfg(struct wl1251 *wl)
{
- struct wl1251_acx_config_memory mem_conf;
+ struct wl1251_acx_config_memory *mem_conf;
int ret, i;
- wl12xx_debug(DEBUG_ACX, "wl1251 mem cfg");
+ wl1251_debug(DEBUG_ACX, "wl1251 mem cfg");
+
+ mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL);
+ if (!mem_conf) {
+ ret = -ENOMEM;
+ goto out;
+ }
/* memory config */
- mem_conf.mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
- mem_conf.mem_config.rx_mem_block_num = 35;
- mem_conf.mem_config.tx_min_mem_block_num = 64;
- mem_conf.mem_config.num_tx_queues = MAX_TX_QUEUES;
- mem_conf.mem_config.host_if_options = HOSTIF_PKT_RING;
- mem_conf.mem_config.num_ssid_profiles = 1;
- mem_conf.mem_config.debug_buffer_size =
+ mem_conf->mem_config.num_stations = cpu_to_le16(DEFAULT_NUM_STATIONS);
+ mem_conf->mem_config.rx_mem_block_num = 35;
+ mem_conf->mem_config.tx_min_mem_block_num = 64;
+ mem_conf->mem_config.num_tx_queues = MAX_TX_QUEUES;
+ mem_conf->mem_config.host_if_options = HOSTIF_PKT_RING;
+ mem_conf->mem_config.num_ssid_profiles = 1;
+ mem_conf->mem_config.debug_buffer_size =
cpu_to_le16(TRACE_BUFFER_MAX_SIZE);
/* RX queue config */
- mem_conf.rx_queue_config.dma_address = 0;
- mem_conf.rx_queue_config.num_descs = ACX_RX_DESC_DEF;
- mem_conf.rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
- mem_conf.rx_queue_config.type = DEFAULT_RXQ_TYPE;
+ mem_conf->rx_queue_config.dma_address = 0;
+ mem_conf->rx_queue_config.num_descs = ACX_RX_DESC_DEF;
+ mem_conf->rx_queue_config.priority = DEFAULT_RXQ_PRIORITY;
+ mem_conf->rx_queue_config.type = DEFAULT_RXQ_TYPE;
/* TX queue config */
for (i = 0; i < MAX_TX_QUEUES; i++) {
- mem_conf.tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
- mem_conf.tx_queue_config[i].attributes = i;
+ mem_conf->tx_queue_config[i].num_descs = ACX_TX_DESC_DEF;
+ mem_conf->tx_queue_config[i].attributes = i;
}
- mem_conf.header.id = ACX_MEM_CFG;
- mem_conf.header.len = sizeof(struct wl1251_acx_config_memory) -
- sizeof(struct acx_header);
- mem_conf.header.len -=
- (MAX_TX_QUEUE_CONFIGS - mem_conf.mem_config.num_tx_queues) *
- sizeof(struct wl1251_acx_tx_queue_config);
-
- ret = wl12xx_cmd_configure(wl, &mem_conf,
- sizeof(struct wl1251_acx_config_memory));
- if (ret < 0)
- wl12xx_warning("wl1251 mem config failed: %d", ret);
+ ret = wl1251_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
+ sizeof(*mem_conf));
+ if (ret < 0) {
+ wl1251_warning("wl1251 mem config failed: %d", ret);
+ goto out;
+ }
+out:
+ kfree(mem_conf);
return ret;
}
-static int wl1251_hw_init_mem_config(struct wl12xx *wl)
+static int wl1251_hw_init_mem_config(struct wl1251 *wl)
{
int ret;
@@ -350,15 +350,15 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl)
wl->target_mem_map = kzalloc(sizeof(struct wl1251_acx_mem_map),
GFP_KERNEL);
if (!wl->target_mem_map) {
- wl12xx_error("couldn't allocate target memory map");
+ wl1251_error("couldn't allocate target memory map");
return -ENOMEM;
}
/* we now ask for the firmware built memory map */
- ret = wl12xx_acx_mem_map(wl, wl->target_mem_map,
+ ret = wl1251_acx_mem_map(wl, wl->target_mem_map,
sizeof(struct wl1251_acx_mem_map));
if (ret < 0) {
- wl12xx_error("couldn't retrieve firmware memory map");
+ wl1251_error("couldn't retrieve firmware memory map");
kfree(wl->target_mem_map);
wl->target_mem_map = NULL;
return ret;
@@ -367,19 +367,19 @@ static int wl1251_hw_init_mem_config(struct wl12xx *wl)
return 0;
}
-static void wl1251_set_ecpu_ctrl(struct wl12xx *wl, u32 flag)
+static void wl1251_set_ecpu_ctrl(struct wl1251 *wl, u32 flag)
{
u32 cpu_ctrl;
/* 10.5.0 run the firmware (I) */
- cpu_ctrl = wl12xx_reg_read32(wl, ACX_REG_ECPU_CONTROL);
+ cpu_ctrl = wl1251_reg_read32(wl, ACX_REG_ECPU_CONTROL);
/* 10.5.1 run the firmware (II) */
cpu_ctrl &= ~flag;
- wl12xx_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
+ wl1251_reg_write32(wl, ACX_REG_ECPU_CONTROL, cpu_ctrl);
}
-static void wl1251_target_enable_interrupts(struct wl12xx *wl)
+static void wl1251_target_enable_interrupts(struct wl1251 *wl)
{
/* Enable target's interrupts */
wl->intr_mask = WL1251_ACX_INTR_RX0_DATA |
@@ -388,52 +388,60 @@ static void wl1251_target_enable_interrupts(struct wl12xx *wl)
WL1251_ACX_INTR_EVENT_A |
WL1251_ACX_INTR_EVENT_B |
WL1251_ACX_INTR_INIT_COMPLETE;
- wl12xx_boot_target_enable_interrupts(wl);
+ wl1251_boot_target_enable_interrupts(wl);
+}
+
+static void wl1251_fw_version(struct wl1251 *wl)
+{
+ wl1251_acx_fw_version(wl, wl->chip.fw_ver, sizeof(wl->chip.fw_ver));
}
static void wl1251_irq_work(struct work_struct *work)
{
u32 intr;
- struct wl12xx *wl =
- container_of(work, struct wl12xx, irq_work);
+ struct wl1251 *wl =
+ container_of(work, struct wl1251, irq_work);
+ int ret;
mutex_lock(&wl->mutex);
- wl12xx_debug(DEBUG_IRQ, "IRQ work");
+ wl1251_debug(DEBUG_IRQ, "IRQ work");
- if (wl->state == WL12XX_STATE_OFF)
+ if (wl->state == WL1251_STATE_OFF)
goto out;
- wl12xx_ps_elp_wakeup(wl);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, WL1251_ACX_INTR_ALL);
- intr = wl12xx_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
- wl12xx_debug(DEBUG_IRQ, "intr: 0x%x", intr);
+ intr = wl1251_reg_read32(wl, ACX_REG_INTERRUPT_CLEAR);
+ wl1251_debug(DEBUG_IRQ, "intr: 0x%x", intr);
if (wl->data_path) {
- wl12xx_spi_mem_read(wl, wl->data_path->rx_control_addr,
- &wl->rx_counter, sizeof(u32));
+ wl->rx_counter =
+ wl1251_mem_read32(wl, wl->data_path->rx_control_addr);
- /* We handle a frmware bug here */
+ /* We handle a firmware bug here */
switch ((wl->rx_counter - wl->rx_handled) & 0xf) {
case 0:
- wl12xx_debug(DEBUG_IRQ, "RX: FW and host in sync");
+ wl1251_debug(DEBUG_IRQ, "RX: FW and host in sync");
intr &= ~WL1251_ACX_INTR_RX0_DATA;
intr &= ~WL1251_ACX_INTR_RX1_DATA;
break;
case 1:
- wl12xx_debug(DEBUG_IRQ, "RX: FW +1");
+ wl1251_debug(DEBUG_IRQ, "RX: FW +1");
intr |= WL1251_ACX_INTR_RX0_DATA;
intr &= ~WL1251_ACX_INTR_RX1_DATA;
break;
case 2:
- wl12xx_debug(DEBUG_IRQ, "RX: FW +2");
+ wl1251_debug(DEBUG_IRQ, "RX: FW +2");
intr |= WL1251_ACX_INTR_RX0_DATA;
intr |= WL1251_ACX_INTR_RX1_DATA;
break;
default:
- wl12xx_warning("RX: FW and host out of sync: %d",
+ wl1251_warning("RX: FW and host out of sync: %d",
wl->rx_counter - wl->rx_handled);
break;
}
@@ -441,49 +449,50 @@ static void wl1251_irq_work(struct work_struct *work)
wl->rx_handled = wl->rx_counter;
- wl12xx_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
+ wl1251_debug(DEBUG_IRQ, "RX counter: %d", wl->rx_counter);
}
intr &= wl->intr_mask;
if (intr == 0) {
- wl12xx_debug(DEBUG_IRQ, "INTR is 0");
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
+ wl1251_debug(DEBUG_IRQ, "INTR is 0");
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK,
~(wl->intr_mask));
goto out_sleep;
}
if (intr & WL1251_ACX_INTR_RX0_DATA) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
- wl12xx_rx(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX0_DATA");
+ wl1251_rx(wl);
}
if (intr & WL1251_ACX_INTR_RX1_DATA) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
- wl12xx_rx(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_RX1_DATA");
+ wl1251_rx(wl);
}
if (intr & WL1251_ACX_INTR_TX_RESULT) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
- wl12xx_tx_complete(wl);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_TX_RESULT");
+ wl1251_tx_complete(wl);
}
if (intr & (WL1251_ACX_INTR_EVENT_A | WL1251_ACX_INTR_EVENT_B)) {
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_EVENT (0x%x)", intr);
if (intr & WL1251_ACX_INTR_EVENT_A)
- wl12xx_event_handle(wl, 0);
+ wl1251_event_handle(wl, 0);
else
- wl12xx_event_handle(wl, 1);
+ wl1251_event_handle(wl, 1);
}
if (intr & WL1251_ACX_INTR_INIT_COMPLETE)
- wl12xx_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
+ wl1251_debug(DEBUG_IRQ, "WL1251_ACX_INTR_INIT_COMPLETE");
- wl12xx_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
+ wl1251_reg_write32(wl, ACX_REG_INTERRUPT_MASK, ~(wl->intr_mask));
out_sleep:
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
+
out:
mutex_unlock(&wl->mutex);
}
@@ -520,40 +529,45 @@ static int wl1251_hw_init_txq_fill(u8 qid,
(QOS_TX_LOW_VO_DEF * num_blocks) / 100;
break;
default:
- wl12xx_error("Invalid TX queue id: %d", qid);
+ wl1251_error("Invalid TX queue id: %d", qid);
return -EINVAL;
}
return 0;
}
-static int wl1251_hw_init_tx_queue_config(struct wl12xx *wl)
+static int wl1251_hw_init_tx_queue_config(struct wl1251 *wl)
{
- struct acx_tx_queue_qos_config config;
+ struct acx_tx_queue_qos_config *config;
struct wl1251_acx_mem_map *wl_mem_map = wl->target_mem_map;
int ret, i;
- wl12xx_debug(DEBUG_ACX, "acx tx queue config");
+ wl1251_debug(DEBUG_ACX, "acx tx queue config");
- config.header.id = ACX_TX_QUEUE_CFG;
- config.header.len = sizeof(struct acx_tx_queue_qos_config) -
- sizeof(struct acx_header);
+ config = kzalloc(sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ ret = -ENOMEM;
+ goto out;
+ }
for (i = 0; i < MAX_NUM_OF_AC; i++) {
- ret = wl1251_hw_init_txq_fill(i, &config,
+ ret = wl1251_hw_init_txq_fill(i, config,
wl_mem_map->num_tx_mem_blocks);
if (ret < 0)
- return ret;
+ goto out;
- ret = wl12xx_cmd_configure(wl, &config, sizeof(config));
+ ret = wl1251_cmd_configure(wl, ACX_TX_QUEUE_CFG,
+ config, sizeof(*config));
if (ret < 0)
- return ret;
+ goto out;
}
- return 0;
+out:
+ kfree(config);
+ return ret;
}
-static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
+static int wl1251_hw_init_data_path_config(struct wl1251 *wl)
{
int ret;
@@ -561,11 +575,11 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
wl->data_path = kzalloc(sizeof(struct acx_data_path_params_resp),
GFP_KERNEL);
if (!wl->data_path) {
- wl12xx_error("Couldnt allocate data path parameters");
+ wl1251_error("Couldn't allocate data path parameters");
return -ENOMEM;
}
- ret = wl12xx_acx_data_path_params(wl, wl->data_path);
+ ret = wl1251_acx_data_path_params(wl, wl->data_path);
if (ret < 0) {
kfree(wl->data_path);
wl->data_path = NULL;
@@ -575,17 +589,17 @@ static int wl1251_hw_init_data_path_config(struct wl12xx *wl)
return 0;
}
-static int wl1251_hw_init(struct wl12xx *wl)
+static int wl1251_hw_init(struct wl1251 *wl)
{
struct wl1251_acx_mem_map *wl_mem_map;
int ret;
- ret = wl12xx_hw_init_hwenc_config(wl);
+ ret = wl1251_hw_init_hwenc_config(wl);
if (ret < 0)
return ret;
/* Template settings */
- ret = wl12xx_hw_init_templates_config(wl);
+ ret = wl1251_hw_init_templates_config(wl);
if (ret < 0)
return ret;
@@ -600,7 +614,7 @@ static int wl1251_hw_init(struct wl12xx *wl)
goto out_free_memmap;
/* RX config */
- ret = wl12xx_hw_init_rx_config(wl,
+ ret = wl1251_hw_init_rx_config(wl,
RX_CFG_PROMISCUOUS | RX_CFG_TSF,
RX_FILTER_OPTION_DEF);
/* RX_CONFIG_OPTION_ANY_DST_ANY_BSS,
@@ -614,42 +628,42 @@ static int wl1251_hw_init(struct wl12xx *wl)
goto out_free_data_path;
/* PHY layer config */
- ret = wl12xx_hw_init_phy_config(wl);
+ ret = wl1251_hw_init_phy_config(wl);
if (ret < 0)
goto out_free_data_path;
/* Beacon filtering */
- ret = wl12xx_hw_init_beacon_filter(wl);
+ ret = wl1251_hw_init_beacon_filter(wl);
if (ret < 0)
goto out_free_data_path;
/* Bluetooth WLAN coexistence */
- ret = wl12xx_hw_init_pta(wl);
+ ret = wl1251_hw_init_pta(wl);
if (ret < 0)
goto out_free_data_path;
/* Energy detection */
- ret = wl12xx_hw_init_energy_detection(wl);
+ ret = wl1251_hw_init_energy_detection(wl);
if (ret < 0)
goto out_free_data_path;
/* Beacons and boradcast settings */
- ret = wl12xx_hw_init_beacon_broadcast(wl);
+ ret = wl1251_hw_init_beacon_broadcast(wl);
if (ret < 0)
goto out_free_data_path;
/* Enable data path */
- ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
+ ret = wl1251_cmd_data_path(wl, wl->channel, 1);
if (ret < 0)
goto out_free_data_path;
/* Default power state */
- ret = wl12xx_hw_init_power_auth(wl);
+ ret = wl1251_hw_init_power_auth(wl);
if (ret < 0)
goto out_free_data_path;
wl_mem_map = wl->target_mem_map;
- wl12xx_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
+ wl1251_info("%d tx blocks at 0x%x, %d rx blocks at 0x%x",
wl_mem_map->num_tx_mem_blocks,
wl->data_path->tx_control_addr,
wl_mem_map->num_rx_mem_blocks,
@@ -666,7 +680,7 @@ static int wl1251_hw_init(struct wl12xx *wl)
return ret;
}
-static int wl1251_plt_init(struct wl12xx *wl)
+static int wl1251_plt_init(struct wl1251 *wl)
{
int ret;
@@ -674,14 +688,14 @@ static int wl1251_plt_init(struct wl12xx *wl)
if (ret < 0)
return ret;
- ret = wl12xx_cmd_data_path(wl, wl->channel, 1);
+ ret = wl1251_cmd_data_path(wl, wl->channel, 1);
if (ret < 0)
return ret;
return 0;
}
-void wl1251_setup(struct wl12xx *wl)
+void wl1251_setup(struct wl1251 *wl)
{
/* FIXME: Is it better to use strncpy here or is this ok? */
wl->chip.fw_filename = WL1251_FW_NAME;
@@ -701,9 +715,14 @@ void wl1251_setup(struct wl12xx *wl)
wl->chip.op_target_enable_interrupts = wl1251_target_enable_interrupts;
wl->chip.op_hw_init = wl1251_hw_init;
wl->chip.op_plt_init = wl1251_plt_init;
+ wl->chip.op_fw_version = wl1251_fw_version;
+ wl->chip.op_tx_flush = wl1251_tx_flush;
+ wl->chip.op_cmd_join = wl1251_cmd_join;
wl->chip.p_table = wl1251_part_table;
wl->chip.acx_reg_table = wl1251_acx_reg_table;
INIT_WORK(&wl->irq_work, wl1251_irq_work);
+ INIT_WORK(&wl->tx_work, wl1251_tx_work);
+
}
diff --git a/drivers/net/wireless/wl12xx/wl1251_ops.h b/drivers/net/wireless/wl12xx/wl1251_ops.h
new file mode 100644
index 00000000000..68183c472e4
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1251_ops.h
@@ -0,0 +1,165 @@
+/*
+ * This file is part of wl1251
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Kalle Valo <kalle.valo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1251_OPS_H__
+#define __WL1251_OPS_H__
+
+#include <linux/bitops.h>
+
+#include "wl1251.h"
+#include "wl1251_acx.h"
+
+#define WL1251_FW_NAME "wl1251-fw.bin"
+#define WL1251_NVS_NAME "wl1251-nvs.bin"
+
+#define WL1251_POWER_ON_SLEEP 10 /* in miliseconds */
+
+void wl1251_setup(struct wl1251 *wl);
+
+
+struct wl1251_acx_memory {
+ __le16 num_stations; /* number of STAs to be supported. */
+ u16 reserved_1;
+
+ /*
+ * Nmber of memory buffers for the RX mem pool.
+ * The actual number may be less if there are
+ * not enough blocks left for the minimum num
+ * of TX ones.
+ */
+ u8 rx_mem_block_num;
+ u8 reserved_2;
+ u8 num_tx_queues; /* From 1 to 16 */
+ u8 host_if_options; /* HOST_IF* */
+ u8 tx_min_mem_block_num;
+ u8 num_ssid_profiles;
+ __le16 debug_buffer_size;
+} __attribute__ ((packed));
+
+
+#define ACX_RX_DESC_MIN 1
+#define ACX_RX_DESC_MAX 127
+#define ACX_RX_DESC_DEF 32
+struct wl1251_acx_rx_queue_config {
+ u8 num_descs;
+ u8 pad;
+ u8 type;
+ u8 priority;
+ __le32 dma_address;
+} __attribute__ ((packed));
+
+#define ACX_TX_DESC_MIN 1
+#define ACX_TX_DESC_MAX 127
+#define ACX_TX_DESC_DEF 16
+struct wl1251_acx_tx_queue_config {
+ u8 num_descs;
+ u8 pad[2];
+ u8 attributes;
+} __attribute__ ((packed));
+
+#define MAX_TX_QUEUE_CONFIGS 5
+#define MAX_TX_QUEUES 4
+struct wl1251_acx_config_memory {
+ struct acx_header header;
+
+ struct wl1251_acx_memory mem_config;
+ struct wl1251_acx_rx_queue_config rx_queue_config;
+ struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
+} __attribute__ ((packed));
+
+struct wl1251_acx_mem_map {
+ struct acx_header header;
+
+ void *code_start;
+ void *code_end;
+
+ void *wep_defkey_start;
+ void *wep_defkey_end;
+
+ void *sta_table_start;
+ void *sta_table_end;
+
+ void *packet_template_start;
+ void *packet_template_end;
+
+ void *queue_memory_start;
+ void *queue_memory_end;
+
+ void *packet_memory_pool_start;
+ void *packet_memory_pool_end;
+
+ void *debug_buffer1_start;
+ void *debug_buffer1_end;
+
+ void *debug_buffer2_start;
+ void *debug_buffer2_end;
+
+ /* Number of blocks FW allocated for TX packets */
+ u32 num_tx_mem_blocks;
+
+ /* Number of blocks FW allocated for RX packets */
+ u32 num_rx_mem_blocks;
+} __attribute__ ((packed));
+
+/*************************************************************************
+
+ Host Interrupt Register (WiLink -> Host)
+
+**************************************************************************/
+
+/* RX packet is ready in Xfer buffer #0 */
+#define WL1251_ACX_INTR_RX0_DATA BIT(0)
+
+/* TX result(s) are in the TX complete buffer */
+#define WL1251_ACX_INTR_TX_RESULT BIT(1)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_TX_XFR BIT(2)
+
+/* RX packet is ready in Xfer buffer #1 */
+#define WL1251_ACX_INTR_RX1_DATA BIT(3)
+
+/* Event was entered to Event MBOX #A */
+#define WL1251_ACX_INTR_EVENT_A BIT(4)
+
+/* Event was entered to Event MBOX #B */
+#define WL1251_ACX_INTR_EVENT_B BIT(5)
+
+/* OBSOLETE */
+#define WL1251_ACX_INTR_WAKE_ON_HOST BIT(6)
+
+/* Trace meassge on MBOX #A */
+#define WL1251_ACX_INTR_TRACE_A BIT(7)
+
+/* Trace meassge on MBOX #B */
+#define WL1251_ACX_INTR_TRACE_B BIT(8)
+
+/* Command processing completion */
+#define WL1251_ACX_INTR_CMD_COMPLETE BIT(9)
+
+/* Init sequence is done */
+#define WL1251_ACX_INTR_INIT_COMPLETE BIT(14)
+
+#define WL1251_ACX_INTR_ALL 0xFFFFFFFF
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/wl1251_ps.c
index 83a10117330..68ff7f1900e 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -22,25 +22,25 @@
*/
#include "reg.h"
-#include "ps.h"
-#include "spi.h"
+#include "wl1251_ps.h"
+#include "wl1251_spi.h"
-#define WL12XX_WAKEUP_TIMEOUT 2000
+#define WL1251_WAKEUP_TIMEOUT 2000
/* Routines to toggle sleep mode while in ELP */
-void wl12xx_ps_elp_sleep(struct wl12xx *wl)
+void wl1251_ps_elp_sleep(struct wl1251 *wl)
{
if (wl->elp || !wl->psm)
return;
- wl12xx_debug(DEBUG_PSM, "chip to elp");
+ wl1251_debug(DEBUG_PSM, "chip to elp");
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP);
wl->elp = true;
}
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
+int wl1251_ps_elp_wakeup(struct wl1251 *wl)
{
unsigned long timeout;
u32 elp_reg;
@@ -48,13 +48,13 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
if (!wl->elp)
return 0;
- wl12xx_debug(DEBUG_PSM, "waking up chip from elp");
+ wl1251_debug(DEBUG_PSM, "waking up chip from elp");
- timeout = jiffies + msecs_to_jiffies(WL12XX_WAKEUP_TIMEOUT);
+ timeout = jiffies + msecs_to_jiffies(WL1251_WAKEUP_TIMEOUT);
- wl12xx_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
+ wl1251_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_WAKE_UP);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
/*
* FIXME: we should wait for irq from chip but, as a temporary
@@ -62,40 +62,36 @@ int wl12xx_ps_elp_wakeup(struct wl12xx *wl)
*/
while (!(elp_reg & ELPCTRL_WLAN_READY)) {
if (time_after(jiffies, timeout)) {
- wl12xx_error("elp wakeup timeout");
+ wl1251_error("elp wakeup timeout");
return -ETIMEDOUT;
}
msleep(1);
- elp_reg = wl12xx_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
+ elp_reg = wl1251_read32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR);
}
- wl12xx_debug(DEBUG_PSM, "wakeup time: %u ms",
+ wl1251_debug(DEBUG_PSM, "wakeup time: %u ms",
jiffies_to_msecs(jiffies) -
- (jiffies_to_msecs(timeout) - WL12XX_WAKEUP_TIMEOUT));
+ (jiffies_to_msecs(timeout) - WL1251_WAKEUP_TIMEOUT));
wl->elp = false;
return 0;
}
-static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
+static int wl1251_ps_set_elp(struct wl1251 *wl, bool enable)
{
int ret;
if (enable) {
- wl12xx_debug(DEBUG_PSM, "sleep auth psm/elp");
+ wl1251_debug(DEBUG_PSM, "sleep auth psm/elp");
- /*
- * FIXME: we should PSM_ELP, but because of firmware wakeup
- * problems let's use only PSM_PS
- */
- ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_PS);
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
if (ret < 0)
return ret;
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
} else {
- wl12xx_debug(DEBUG_PSM, "sleep auth cam");
+ wl1251_debug(DEBUG_PSM, "sleep auth cam");
/*
* When the target is in ELP, we can only
@@ -104,9 +100,9 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
* changing the power authorization.
*/
- wl12xx_ps_elp_wakeup(wl);
+ wl1251_ps_elp_wakeup(wl);
- ret = wl12xx_acx_sleep_auth(wl, WL12XX_PSM_CAM);
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_CAM);
if (ret < 0)
return ret;
}
@@ -114,18 +110,18 @@ static int wl12xx_ps_set_elp(struct wl12xx *wl, bool enable)
return 0;
}
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
{
int ret;
switch (mode) {
case STATION_POWER_SAVE_MODE:
- wl12xx_debug(DEBUG_PSM, "entering psm");
- ret = wl12xx_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ wl1251_debug(DEBUG_PSM, "entering psm");
+ ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
if (ret < 0)
return ret;
- ret = wl12xx_ps_set_elp(wl, true);
+ ret = wl1251_ps_set_elp(wl, true);
if (ret < 0)
return ret;
@@ -133,12 +129,12 @@ int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode)
break;
case STATION_ACTIVE_MODE:
default:
- wl12xx_debug(DEBUG_PSM, "leaving psm");
- ret = wl12xx_ps_set_elp(wl, false);
+ wl1251_debug(DEBUG_PSM, "leaving psm");
+ ret = wl1251_ps_set_elp(wl, false);
if (ret < 0)
return ret;
- ret = wl12xx_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/wl1251_ps.h
index 5d7c5255383..db036fe12f2 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/wl1251_ps.h
@@ -1,8 +1,8 @@
-#ifndef __WL12XX_PS_H__
-#define __WL12XX_PS_H__
+#ifndef __WL1251_PS_H__
+#define __WL1251_PS_H__
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,12 +25,12 @@
*
*/
-#include "wl12xx.h"
-#include "acx.h"
+#include "wl1251.h"
+#include "wl1251_acx.h"
-int wl12xx_ps_set_mode(struct wl12xx *wl, enum acx_ps_mode mode);
-void wl12xx_ps_elp_sleep(struct wl12xx *wl);
-int wl12xx_ps_elp_wakeup(struct wl12xx *wl);
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
+void wl1251_ps_elp_sleep(struct wl1251 *wl);
+int wl1251_ps_elp_wakeup(struct wl1251 *wl);
-#endif /* __WL12XX_PS_H__ */
+#endif /* __WL1251_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/wl1251_rx.c
index 981ea259eb8..0dbb483a097 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,13 +25,14 @@
#include <linux/skbuff.h>
#include <net/mac80211.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "rx.h"
+#include "wl1251_spi.h"
+#include "wl1251_rx.h"
+#include "wl1251_acx.h"
-static void wl12xx_rx_header(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_header(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc)
{
u32 rx_packet_ring_addr;
@@ -39,15 +40,17 @@ static void wl12xx_rx_header(struct wl12xx *wl,
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, desc,
- sizeof(struct wl12xx_rx_descriptor));
+ wl1251_spi_mem_read(wl, rx_packet_ring_addr, desc, sizeof(*desc));
}
-static void wl12xx_rx_status(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc,
+static void wl1251_rx_status(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc,
struct ieee80211_rx_status *status,
u8 beacon)
{
+ u64 mactime;
+ int ret;
+
memset(status, 0, sizeof(struct ieee80211_rx_status));
status->band = IEEE80211_BAND_2GHZ;
@@ -62,32 +65,14 @@ static void wl12xx_rx_status(struct wl12xx *wl,
* this one must be atomic, while our SPI routines can sleep.
*/
if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) {
- u64 mactime;
- int ret;
- struct wl12xx_command cmd;
- struct acx_tsf_info *tsf_info;
-
- memset(&cmd, 0, sizeof(cmd));
-
- ret = wl12xx_cmd_interrogate(wl, ACX_TSF_INFO,
- sizeof(struct acx_tsf_info),
- &cmd);
- if (ret < 0) {
- wl12xx_warning("ACX_FW_REV interrogate failed");
- return;
- }
-
- tsf_info = (struct acx_tsf_info *)&(cmd.parameters);
-
- mactime = tsf_info->current_tsf_lsb |
- (tsf_info->current_tsf_msb << 31);
-
- status->mactime = mactime;
+ ret = wl1251_acx_tsf_info(wl, &mactime);
+ if (ret == 0)
+ status->mactime = mactime;
}
status->signal = desc->rssi;
- status->qual = (desc->rssi - WL12XX_RX_MIN_RSSI) * 100 /
- (WL12XX_RX_MAX_RSSI - WL12XX_RX_MIN_RSSI);
+ status->qual = (desc->rssi - WL1251_RX_MIN_RSSI) * 100 /
+ (WL1251_RX_MAX_RSSI - WL1251_RX_MIN_RSSI);
status->qual = min(status->qual, 100);
status->qual = max(status->qual, 0);
@@ -118,8 +103,8 @@ static void wl12xx_rx_status(struct wl12xx *wl,
/* FIXME: set status->rate_idx */
}
-static void wl12xx_rx_body(struct wl12xx *wl,
- struct wl12xx_rx_descriptor *desc)
+static void wl1251_rx_body(struct wl1251 *wl,
+ struct wl1251_rx_descriptor *desc)
{
struct sk_buff *skb;
struct ieee80211_rx_status status;
@@ -127,12 +112,12 @@ static void wl12xx_rx_body(struct wl12xx *wl,
u16 length, *fc;
u32 curr_id, last_id_inc, rx_packet_ring_addr;
- length = WL12XX_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH);
+ length = WL1251_RX_ALIGN(desc->length - PLCP_HEADER_LENGTH);
curr_id = (desc->flags & RX_DESC_SEQNUM_MASK) >> RX_DESC_PACKETID_SHIFT;
last_id_inc = (wl->rx_last_id + 1) % (RX_MAX_PACKET_ID + 1);
if (last_id_inc != curr_id) {
- wl12xx_warning("curr ID:%d, last ID inc:%d",
+ wl1251_warning("curr ID:%d, last ID inc:%d",
curr_id, last_id_inc);
wl->rx_last_id = curr_id;
} else {
@@ -140,18 +125,18 @@ static void wl12xx_rx_body(struct wl12xx *wl,
}
rx_packet_ring_addr = wl->data_path->rx_packet_ring_addr +
- sizeof(struct wl12xx_rx_descriptor) + 20;
+ sizeof(struct wl1251_rx_descriptor) + 20;
if (wl->rx_current_buffer)
rx_packet_ring_addr += wl->data_path->rx_packet_ring_chunk_size;
skb = dev_alloc_skb(length);
if (!skb) {
- wl12xx_error("Couldn't allocate RX frame");
+ wl1251_error("Couldn't allocate RX frame");
return;
}
rx_buffer = skb_put(skb, length);
- wl12xx_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
+ wl1251_spi_mem_read(wl, rx_packet_ring_addr, rx_buffer, length);
/* The actual lenght doesn't include the target's alignment */
skb->len = desc->length - PLCP_HEADER_LENGTH;
@@ -161,15 +146,16 @@ static void wl12xx_rx_body(struct wl12xx *wl,
if ((*fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
beacon = 1;
- wl12xx_rx_status(wl, desc, &status, beacon);
+ wl1251_rx_status(wl, desc, &status, beacon);
- wl12xx_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
+ wl1251_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
beacon ? "beacon" : "");
- ieee80211_rx(wl->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx(wl->hw, skb);
}
-static void wl12xx_rx_ack(struct wl12xx *wl)
+static void wl1251_rx_ack(struct wl1251 *wl)
{
u32 data, addr;
@@ -181,28 +167,30 @@ static void wl12xx_rx_ack(struct wl12xx *wl)
data = INTR_TRIG_RX_PROC0;
}
- wl12xx_reg_write32(wl, addr, data);
+ wl1251_reg_write32(wl, addr, data);
/* Toggle buffer ring */
wl->rx_current_buffer = !wl->rx_current_buffer;
}
-void wl12xx_rx(struct wl12xx *wl)
+void wl1251_rx(struct wl1251 *wl)
{
- struct wl12xx_rx_descriptor rx_desc;
+ struct wl1251_rx_descriptor *rx_desc;
- if (wl->state != WL12XX_STATE_ON)
+ if (wl->state != WL1251_STATE_ON)
return;
+ rx_desc = wl->rx_descriptor;
+
/* We first read the frame's header */
- wl12xx_rx_header(wl, &rx_desc);
+ wl1251_rx_header(wl, rx_desc);
/* Now we can read the body */
- wl12xx_rx_body(wl, &rx_desc);
+ wl1251_rx_body(wl, rx_desc);
/* Finally, we need to ACK the RX */
- wl12xx_rx_ack(wl);
+ wl1251_rx_ack(wl);
return;
}
diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h
index 8a23fdea501..563a3fde40f 100644
--- a/drivers/net/wireless/wl12xx/rx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,11 +22,13 @@
*
*/
-#ifndef __WL12XX_RX_H__
-#define __WL12XX_RX_H__
+#ifndef __WL1251_RX_H__
+#define __WL1251_RX_H__
#include <linux/bitops.h>
+#include "wl1251.h"
+
/*
* RX PATH
*
@@ -43,12 +45,12 @@
* 4) The target prepares the next RX packet.
*/
-#define WL12XX_RX_MAX_RSSI -30
-#define WL12XX_RX_MIN_RSSI -95
+#define WL1251_RX_MAX_RSSI -30
+#define WL1251_RX_MIN_RSSI -95
-#define WL12XX_RX_ALIGN_TO 4
-#define WL12XX_RX_ALIGN(len) (((len) + WL12XX_RX_ALIGN_TO - 1) & \
- ~(WL12XX_RX_ALIGN_TO - 1))
+#define WL1251_RX_ALIGN_TO 4
+#define WL1251_RX_ALIGN(len) (((len) + WL1251_RX_ALIGN_TO - 1) & \
+ ~(WL1251_RX_ALIGN_TO - 1))
#define SHORT_PREAMBLE_BIT BIT(0)
#define OFDM_RATE_BIT BIT(6)
@@ -72,7 +74,7 @@
#define RX_DESC_MIC_FAIL 0x2000
#define RX_DESC_DECRYPT_FAIL 0x4000
-struct wl12xx_rx_descriptor {
+struct wl1251_rx_descriptor {
u32 timestamp; /* In microseconds */
u16 length; /* Paylod length, including headers */
u16 flags;
@@ -86,7 +88,7 @@ struct wl12xx_rx_descriptor {
u8 type;
/*
- * Recevied Rate:
+ * Received Rate:
* 0x0A - 1MBPS
* 0x14 - 2MBPS
* 0x37 - 5_5MBPS
@@ -117,6 +119,6 @@ struct wl12xx_rx_descriptor {
u8 snr; /* in dB */
} __attribute__ ((packed));
-void wl12xx_rx(struct wl12xx *wl);
+void wl1251_rx(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/wl1251_spi.c
index abdf171a47e..c5da79dbc49 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (C) 2008 Nokia Corporation
*
@@ -25,13 +25,11 @@
#include <linux/crc7.h>
#include <linux/spi/spi.h>
-#include "wl12xx.h"
-#include "wl12xx_80211.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "ps.h"
+#include "wl1251_spi.h"
-static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
+static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr)
{
/* If the address is lower than REGISTERS_BASE, it means that this is
* a chip-specific register address, so look it up in the registers
@@ -39,7 +37,7 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
if (addr < REGISTERS_BASE) {
/* Make sure we don't go over the table */
if (addr >= ACX_REG_TABLE_LEN) {
- wl12xx_error("address out of range (%d)", addr);
+ wl1251_error("address out of range (%d)", addr);
return -EINVAL;
}
addr = wl->chip.acx_reg_table[addr];
@@ -48,13 +46,13 @@ static int wl12xx_translate_reg_addr(struct wl12xx *wl, int addr)
return addr - wl->physical_reg_addr + wl->virtual_reg_addr;
}
-static int wl12xx_translate_mem_addr(struct wl12xx *wl, int addr)
+static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr)
{
return addr - wl->physical_mem_addr + wl->virtual_mem_addr;
}
-void wl12xx_spi_reset(struct wl12xx *wl)
+void wl1251_spi_reset(struct wl1251 *wl)
{
u8 *cmd;
struct spi_transfer t;
@@ -62,7 +60,7 @@ void wl12xx_spi_reset(struct wl12xx *wl)
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
- wl12xx_error("could not allocate cmd for spi reset");
+ wl1251_error("could not allocate cmd for spi reset");
return;
}
@@ -77,10 +75,10 @@ void wl12xx_spi_reset(struct wl12xx *wl)
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
+ wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN);
}
-void wl12xx_spi_init(struct wl12xx *wl)
+void wl1251_spi_init(struct wl1251 *wl)
{
u8 crc[WSPI_INIT_CMD_CRC_LEN], *cmd;
struct spi_transfer t;
@@ -88,7 +86,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
cmd = kzalloc(WSPI_INIT_CMD_LEN, GFP_KERNEL);
if (!cmd) {
- wl12xx_error("could not allocate cmd for spi init");
+ wl1251_error("could not allocate cmd for spi init");
return;
}
@@ -131,7 +129,7 @@ void wl12xx_spi_init(struct wl12xx *wl)
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
+ wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN);
}
/* Set the SPI partitions to access the chip addresses
@@ -167,45 +165,47 @@ void wl12xx_spi_init(struct wl12xx *wl)
* | |
*
*/
-void wl12xx_set_partition(struct wl12xx *wl,
+int wl1251_set_partition(struct wl1251 *wl,
u32 mem_start, u32 mem_size,
u32 reg_start, u32 reg_size)
{
- u8 tx_buf[sizeof(u32) + 2 * sizeof(struct wl12xx_partition)];
- struct wl12xx_partition *partition;
+ struct wl1251_partition *partition;
struct spi_transfer t;
struct spi_message m;
+ size_t len, cmd_len;
u32 *cmd;
- size_t len;
int addr;
+ cmd_len = sizeof(u32) + 2 * sizeof(struct wl1251_partition);
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
spi_message_init(&m);
memset(&t, 0, sizeof(t));
- memset(tx_buf, 0, sizeof(tx_buf));
- cmd = (u32 *) tx_buf;
- partition = (struct wl12xx_partition *) (tx_buf + sizeof(u32));
+ partition = (struct wl1251_partition *) (cmd + 1);
addr = HW_ACCESS_PART0_SIZE_ADDR;
- len = 2 * sizeof(struct wl12xx_partition);
+ len = 2 * sizeof(struct wl1251_partition);
*cmd |= WSPI_CMD_WRITE;
*cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
*cmd |= addr & WSPI_CMD_BYTE_ADDR;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
/* Make sure that the two partitions together don't exceed the
* address range */
if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) {
- wl12xx_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
+ wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual"
" address range. Truncating partition[0].");
mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
}
@@ -213,23 +213,23 @@ void wl12xx_set_partition(struct wl12xx *wl,
((mem_start + mem_size) > reg_start)) {
/* Guarantee that the memory partition doesn't overlap the
* registers partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[0] is "
+ wl1251_debug(DEBUG_SPI, "End of partition[0] is "
"overlapping partition[1]. Adjusted.");
mem_size = reg_start - mem_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
} else if ((reg_start < mem_start) &&
((reg_start + reg_size) > mem_start)) {
/* Guarantee that the register partition doesn't overlap the
* memory partition */
- wl12xx_debug(DEBUG_SPI, "End of partition[1] is"
+ wl1251_debug(DEBUG_SPI, "End of partition[1] is"
" overlapping partition[0]. Adjusted.");
reg_size = mem_start - reg_start;
- wl12xx_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
+ wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X",
mem_start, mem_size);
- wl12xx_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
+ wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X",
reg_start, reg_size);
}
@@ -244,36 +244,46 @@ void wl12xx_set_partition(struct wl12xx *wl,
wl->virtual_mem_addr = 0;
wl->virtual_reg_addr = mem_size;
- t.tx_buf = tx_buf;
- t.len = sizeof(tx_buf);
+ t.tx_buf = cmd;
+ t.len = cmd_len;
spi_message_add_tail(&t, &m);
spi_sync(wl->spi, &m);
+
+ kfree(cmd);
+
+ return 0;
}
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[3];
struct spi_message m;
- char busy_buf[TNETWIF_READ_OFFSET_BYTES];
- u32 cmd;
+ u8 *busy_buf;
+ u32 *cmd;
+
+ cmd = &wl->buffer_cmd;
+ busy_buf = wl->buffer_busyword;
+
+ *cmd = 0;
+ *cmd |= WSPI_CMD_READ;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
- cmd = 0;
- cmd |= WSPI_CMD_READ;
- cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = &cmd;
+ t[0].tx_buf = cmd;
t[0].len = 4;
spi_message_add_tail(&t[0], &m);
/* Busy and non busy words read */
t[1].rx_buf = busy_buf;
- t[1].len = TNETWIF_READ_OFFSET_BYTES;
+ t[1].len = WL1251_BUSY_WORD_LEN;
spi_message_add_tail(&t[1], &m);
t[2].rx_buf = buf;
@@ -284,27 +294,32 @@ void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf,
/* FIXME: check busy words */
- wl12xx_dump(DEBUG_SPI, "spi_read cmd -> ", &cmd, sizeof(cmd));
- wl12xx_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
+ wl1251_dump(DEBUG_SPI, "spi_read cmd -> ", cmd, sizeof(*cmd));
+ wl1251_dump(DEBUG_SPI, "spi_read buf <- ", buf, len);
}
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
- size_t len)
+void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed)
{
struct spi_transfer t[2];
struct spi_message m;
- u32 cmd;
+ u32 *cmd;
+
+ cmd = &wl->buffer_cmd;
- cmd = 0;
- cmd |= WSPI_CMD_WRITE;
- cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
- cmd |= addr & WSPI_CMD_BYTE_ADDR;
+ *cmd = 0;
+ *cmd |= WSPI_CMD_WRITE;
+ *cmd |= (len << WSPI_CMD_BYTE_LENGTH_OFFSET) & WSPI_CMD_BYTE_LENGTH;
+ *cmd |= addr & WSPI_CMD_BYTE_ADDR;
+
+ if (fixed)
+ *cmd |= WSPI_CMD_FIXED;
spi_message_init(&m);
memset(t, 0, sizeof(t));
- t[0].tx_buf = &cmd;
- t[0].len = sizeof(cmd);
+ t[0].tx_buf = cmd;
+ t[0].len = sizeof(*cmd);
spi_message_add_tail(&t[0], &m);
t[1].tx_buf = buf;
@@ -313,46 +328,66 @@ void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf,
spi_sync(wl->spi, &m);
- wl12xx_dump(DEBUG_SPI, "spi_write cmd -> ", &cmd, sizeof(cmd));
- wl12xx_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
+ wl1251_dump(DEBUG_SPI, "spi_write cmd -> ", cmd, sizeof(*cmd));
+ wl1251_dump(DEBUG_SPI, "spi_write buf -> ", buf, len);
}
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf,
+void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf,
size_t len)
{
int physical;
- physical = wl12xx_translate_mem_addr(wl, addr);
+ physical = wl1251_translate_mem_addr(wl, addr);
- wl12xx_spi_read(wl, physical, buf, len);
+ wl1251_spi_read(wl, physical, buf, len, false);
}
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf,
+void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf,
size_t len)
{
int physical;
- physical = wl12xx_translate_mem_addr(wl, addr);
+ physical = wl1251_translate_mem_addr(wl, addr);
+
+ wl1251_spi_write(wl, physical, buf, len, false);
+}
+
+void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1251_translate_reg_addr(wl, addr);
+
+ wl1251_spi_read(wl, physical, buf, len, fixed);
+}
+
+void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed)
+{
+ int physical;
+
+ physical = wl1251_translate_reg_addr(wl, addr);
- wl12xx_spi_write(wl, physical, buf, len);
+ wl1251_spi_write(wl, physical, buf, len, fixed);
}
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr)
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr)
{
- return wl12xx_read32(wl, wl12xx_translate_mem_addr(wl, addr));
+ return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr));
}
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_write32(wl, wl12xx_translate_mem_addr(wl, addr), val);
+ wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val);
}
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr)
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr)
{
- return wl12xx_read32(wl, wl12xx_translate_reg_addr(wl, addr));
+ return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr));
}
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val)
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_write32(wl, wl12xx_translate_reg_addr(wl, addr), val);
+ wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val);
}
diff --git a/drivers/net/wireless/wl12xx/spi.h b/drivers/net/wireless/wl12xx/wl1251_spi.h
index fd3227e904a..6e8daf4e108 100644
--- a/drivers/net/wireless/wl12xx/spi.h
+++ b/drivers/net/wireless/wl12xx/wl1251_spi.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,11 +22,11 @@
*
*/
-#ifndef __WL12XX_SPI_H__
-#define __WL12XX_SPI_H__
+#ifndef __WL1251_SPI_H__
+#define __WL1251_SPI_H__
-#include "cmd.h"
-#include "acx.h"
+#include "wl1251_cmd.h"
+#include "wl1251_acx.h"
#include "reg.h"
#define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0
@@ -65,45 +65,51 @@
#define WSPI_INIT_CMD_LEN 8
-#define TNETWIF_READ_OFFSET_BYTES 8
#define HW_ACCESS_WSPI_FIXED_BUSY_LEN \
- ((TNETWIF_READ_OFFSET_BYTES - 4) / sizeof(u32))
+ ((WL1251_BUSY_WORD_LEN - 4) / sizeof(u32))
#define HW_ACCESS_WSPI_INIT_CMD_MASK 0
/* Raw target IO, address is not translated */
-void wl12xx_spi_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_write(struct wl12xx *wl, int addr, void *buf, size_t len);
+void wl1251_spi_write(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed);
+void wl1251_spi_read(struct wl1251 *wl, int addr, void *buf,
+ size_t len, bool fixed);
/* Memory target IO, address is tranlated to partition 0 */
-void wl12xx_spi_mem_read(struct wl12xx *wl, int addr, void *buf, size_t len);
-void wl12xx_spi_mem_write(struct wl12xx *wl, int addr, void *buf, size_t len);
-u32 wl12xx_mem_read32(struct wl12xx *wl, int addr);
-void wl12xx_mem_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1251_spi_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len);
+void wl1251_spi_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len);
+u32 wl1251_mem_read32(struct wl1251 *wl, int addr);
+void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val);
/* Registers IO */
-u32 wl12xx_reg_read32(struct wl12xx *wl, int addr);
-void wl12xx_reg_write32(struct wl12xx *wl, int addr, u32 val);
+void wl1251_spi_reg_read(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+void wl1251_spi_reg_write(struct wl1251 *wl, int addr, void *buf, size_t len,
+ bool fixed);
+u32 wl1251_reg_read32(struct wl1251 *wl, int addr);
+void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val);
/* INIT and RESET words */
-void wl12xx_spi_reset(struct wl12xx *wl);
-void wl12xx_spi_init(struct wl12xx *wl);
-void wl12xx_set_partition(struct wl12xx *wl,
- u32 part_start, u32 part_size,
- u32 reg_start, u32 reg_size);
+void wl1251_spi_reset(struct wl1251 *wl);
+void wl1251_spi_init(struct wl1251 *wl);
+int wl1251_set_partition(struct wl1251 *wl,
+ u32 part_start, u32 part_size,
+ u32 reg_start, u32 reg_size);
-static inline u32 wl12xx_read32(struct wl12xx *wl, int addr)
+static inline u32 wl1251_read32(struct wl1251 *wl, int addr)
{
- u32 response;
+ wl1251_spi_read(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
- wl12xx_spi_read(wl, addr, &response, sizeof(u32));
-
- return response;
+ return wl->buffer_32;
}
-static inline void wl12xx_write32(struct wl12xx *wl, int addr, u32 val)
+static inline void wl1251_write32(struct wl1251 *wl, int addr, u32 val)
{
- wl12xx_spi_write(wl, addr, &val, sizeof(u32));
+ wl->buffer_32 = val;
+ wl1251_spi_write(wl, addr, &wl->buffer_32,
+ sizeof(wl->buffer_32), false);
}
-#endif /* __WL12XX_SPI_H__ */
+#endif /* __WL1251_SPI_H__ */
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/wl1251_tx.c
index 62145e205a8..2652a222383 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.c
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -25,13 +25,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include "wl12xx.h"
+#include "wl1251.h"
#include "reg.h"
-#include "spi.h"
-#include "tx.h"
-#include "ps.h"
+#include "wl1251_spi.h"
+#include "wl1251_tx.h"
+#include "wl1251_ps.h"
-static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
+static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
{
int used, data_in_count;
@@ -52,15 +52,15 @@ static bool wl12xx_tx_double_buffer_busy(struct wl12xx *wl, u32 data_out_count)
return false;
}
-static int wl12xx_tx_path_status(struct wl12xx *wl)
+static int wl1251_tx_path_status(struct wl1251 *wl)
{
u32 status, addr, data_out_count;
bool busy;
addr = wl->data_path->tx_control_addr;
- status = wl12xx_mem_read32(wl, addr);
+ status = wl1251_mem_read32(wl, addr);
data_out_count = status & TX_STATUS_DATA_OUT_COUNT_MASK;
- busy = wl12xx_tx_double_buffer_busy(wl, data_out_count);
+ busy = wl1251_tx_double_buffer_busy(wl, data_out_count);
if (busy)
return -EBUSY;
@@ -68,7 +68,7 @@ static int wl12xx_tx_path_status(struct wl12xx *wl)
return 0;
}
-static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_id(struct wl1251 *wl, struct sk_buff *skb)
{
int i;
@@ -81,7 +81,7 @@ static int wl12xx_tx_id(struct wl12xx *wl, struct sk_buff *skb)
return -EBUSY;
}
-static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
+static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr,
struct ieee80211_tx_info *control, u16 fc)
{
*(u16 *)&tx_hdr->control = 0;
@@ -109,7 +109,7 @@ static void wl12xx_tx_control(struct tx_double_buffer_desc *tx_hdr,
#define MAX_MPDU_HEADER_AND_SECURITY (MAX_MPDU_SECURITY_LENGTH + \
WLAN_QOS_HDR_LEN)
#define HW_BLOCK_SIZE 252
-static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
+static void wl1251_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
{
u16 payload_len, frag_threshold, mem_blocks;
u16 num_mpdus, mem_blocks_per_frag;
@@ -142,7 +142,7 @@ static void wl12xx_tx_frag_block_num(struct tx_double_buffer_desc *tx_hdr)
tx_hdr->num_mem_blocks = mem_blocks;
}
-static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_fill_hdr(struct wl1251 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct tx_double_buffer_desc *tx_hdr;
@@ -153,7 +153,7 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
if (!skb)
return -EINVAL;
- id = wl12xx_tx_id(wl, skb);
+ id = wl1251_tx_id(wl, skb);
if (id < 0)
return id;
@@ -170,14 +170,14 @@ static int wl12xx_tx_fill_hdr(struct wl12xx *wl, struct sk_buff *skb,
/* FIXME: how to get the correct queue id? */
tx_hdr->xmit_queue = 0;
- wl12xx_tx_control(tx_hdr, control, fc);
- wl12xx_tx_frag_block_num(tx_hdr);
+ wl1251_tx_control(tx_hdr, control, fc);
+ wl1251_tx_frag_block_num(tx_hdr);
return 0;
}
/* We copy the packet to the target */
-static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
+static int wl1251_tx_send_packet(struct wl1251 *wl, struct sk_buff *skb,
struct ieee80211_tx_info *control)
{
struct tx_double_buffer_desc *tx_hdr;
@@ -196,12 +196,12 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
u8 *pos;
fc = *(u16 *)(skb->data + sizeof(*tx_hdr));
- tx_hdr->length += WL12XX_TKIP_IV_SPACE;
+ tx_hdr->length += WL1251_TKIP_IV_SPACE;
hdrlen = ieee80211_hdrlen(fc);
- pos = skb_push(skb, WL12XX_TKIP_IV_SPACE);
- memmove(pos, pos + WL12XX_TKIP_IV_SPACE,
+ pos = skb_push(skb, WL1251_TKIP_IV_SPACE);
+ memmove(pos, pos + WL1251_TKIP_IV_SPACE,
sizeof(*tx_hdr) + hdrlen);
}
@@ -211,7 +211,7 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
*/
if (unlikely((long)skb->data & 0x03)) {
int offset = (4 - (long)skb->data) & 0x03;
- wl12xx_debug(DEBUG_TX, "skb offset %d", offset);
+ wl1251_debug(DEBUG_TX, "skb offset %d", offset);
/* check whether the current skb can be used */
if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) {
@@ -221,13 +221,13 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
skb_reserve(skb, offset);
memmove(skb->data, src, skb->len);
} else {
- wl12xx_info("No handler, fixme!");
+ wl1251_info("No handler, fixme!");
return -EINVAL;
}
}
/* Our skb->data at this point includes the HW header */
- len = WL12XX_TX_ALIGN(skb->len);
+ len = WL1251_TX_ALIGN(skb->len);
if (wl->data_in_count & 0x1)
addr = wl->data_path->tx_packet_ring_addr +
@@ -235,15 +235,15 @@ static int wl12xx_tx_send_packet(struct wl12xx *wl, struct sk_buff *skb,
else
addr = wl->data_path->tx_packet_ring_addr;
- wl12xx_spi_mem_write(wl, addr, skb->data, len);
+ wl1251_spi_mem_write(wl, addr, skb->data, len);
- wl12xx_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
+ wl1251_debug(DEBUG_TX, "tx id %u skb 0x%p payload %u rate 0x%x",
tx_hdr->id, skb, tx_hdr->length, tx_hdr->rate);
return 0;
}
-static void wl12xx_tx_trigger(struct wl12xx *wl)
+static void wl1251_tx_trigger(struct wl1251 *wl)
{
u32 data, addr;
@@ -255,7 +255,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
data = INTR_TRIG_TX_PROC0;
}
- wl12xx_reg_write32(wl, addr, data);
+ wl1251_reg_write32(wl, addr, data);
/* Bumping data in */
wl->data_in_count = (wl->data_in_count + 1) &
@@ -263,7 +263,7 @@ static void wl12xx_tx_trigger(struct wl12xx *wl)
}
/* caller must hold wl->mutex */
-static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
+static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
{
struct ieee80211_tx_info *info;
int ret = 0;
@@ -274,51 +274,53 @@ static int wl12xx_tx_frame(struct wl12xx *wl, struct sk_buff *skb)
if (info->control.hw_key) {
idx = info->control.hw_key->hw_key_idx;
if (unlikely(wl->default_key != idx)) {
- ret = wl12xx_acx_default_key(wl, idx);
+ ret = wl1251_acx_default_key(wl, idx);
if (ret < 0)
return ret;
}
}
- ret = wl12xx_tx_path_status(wl);
+ ret = wl1251_tx_path_status(wl);
if (ret < 0)
return ret;
- ret = wl12xx_tx_fill_hdr(wl, skb, info);
+ ret = wl1251_tx_fill_hdr(wl, skb, info);
if (ret < 0)
return ret;
- ret = wl12xx_tx_send_packet(wl, skb, info);
+ ret = wl1251_tx_send_packet(wl, skb, info);
if (ret < 0)
return ret;
- wl12xx_tx_trigger(wl);
+ wl1251_tx_trigger(wl);
return ret;
}
-void wl12xx_tx_work(struct work_struct *work)
+void wl1251_tx_work(struct work_struct *work)
{
- struct wl12xx *wl = container_of(work, struct wl12xx, tx_work);
+ struct wl1251 *wl = container_of(work, struct wl1251, tx_work);
struct sk_buff *skb;
bool woken_up = false;
int ret;
mutex_lock(&wl->mutex);
- if (unlikely(wl->state == WL12XX_STATE_OFF))
+ if (unlikely(wl->state == WL1251_STATE_OFF))
goto out;
while ((skb = skb_dequeue(&wl->tx_queue))) {
if (!woken_up) {
- wl12xx_ps_elp_wakeup(wl);
+ ret = wl1251_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
woken_up = true;
}
- ret = wl12xx_tx_frame(wl, skb);
+ ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
/* firmware buffer is full, stop queues */
- wl12xx_debug(DEBUG_TX, "tx_work: fw buffer full, "
+ wl1251_debug(DEBUG_TX, "tx_work: fw buffer full, "
"stop queues");
ieee80211_stop_queues(wl->hw);
wl->tx_queue_stopped = true;
@@ -332,12 +334,12 @@ void wl12xx_tx_work(struct work_struct *work)
out:
if (woken_up)
- wl12xx_ps_elp_sleep(wl);
+ wl1251_ps_elp_sleep(wl);
mutex_unlock(&wl->mutex);
}
-static const char *wl12xx_tx_parse_status(u8 status)
+static const char *wl1251_tx_parse_status(u8 status)
{
/* 8 bit status field, one character per bit plus null */
static char buf[9];
@@ -365,7 +367,7 @@ static const char *wl12xx_tx_parse_status(u8 status)
return buf;
}
-static void wl12xx_tx_packet_cb(struct wl12xx *wl,
+static void wl1251_tx_packet_cb(struct wl1251 *wl,
struct tx_result *result)
{
struct ieee80211_tx_info *info;
@@ -375,7 +377,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
skb = wl->tx_frames[result->id];
if (skb == NULL) {
- wl12xx_error("SKB for packet %d is NULL", result->id);
+ wl1251_error("SKB for packet %d is NULL", result->id);
return;
}
@@ -396,14 +398,14 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
if (info->control.hw_key &&
info->control.hw_key->alg == ALG_TKIP) {
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(frame + WL12XX_TKIP_IV_SPACE, frame, hdrlen);
- skb_pull(skb, WL12XX_TKIP_IV_SPACE);
+ memmove(frame + WL1251_TKIP_IV_SPACE, frame, hdrlen);
+ skb_pull(skb, WL1251_TKIP_IV_SPACE);
}
- wl12xx_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
+ wl1251_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
" status 0x%x (%s)",
result->id, skb, result->ack_failures, result->rate,
- result->status, wl12xx_tx_parse_status(result->status));
+ result->status, wl1251_tx_parse_status(result->status));
ieee80211_tx_status(wl->hw, skb);
@@ -411,7 +413,7 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
wl->tx_frames[result->id] = NULL;
if (wl->tx_queue_stopped) {
- wl12xx_debug(DEBUG_TX, "cb: queue was stopped");
+ wl1251_debug(DEBUG_TX, "cb: queue was stopped");
skb = skb_dequeue(&wl->tx_queue);
@@ -420,10 +422,10 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
queue empty */
if (skb) {
- ret = wl12xx_tx_frame(wl, skb);
+ ret = wl1251_tx_frame(wl, skb);
if (ret == -EBUSY) {
/* firmware buffer is still full */
- wl12xx_debug(DEBUG_TX, "cb: fw buffer "
+ wl1251_debug(DEBUG_TX, "cb: fw buffer "
"still full");
skb_queue_head(&wl->tx_queue, skb);
return;
@@ -433,23 +435,23 @@ static void wl12xx_tx_packet_cb(struct wl12xx *wl,
}
}
- wl12xx_debug(DEBUG_TX, "cb: waking queues");
+ wl1251_debug(DEBUG_TX, "cb: waking queues");
ieee80211_wake_queues(wl->hw);
wl->tx_queue_stopped = false;
}
}
/* Called upon reception of a TX complete interrupt */
-void wl12xx_tx_complete(struct wl12xx *wl)
+void wl1251_tx_complete(struct wl1251 *wl)
{
int i, result_index, num_complete = 0;
struct tx_result result[FW_TX_CMPLT_BLOCK_SIZE], *result_ptr;
- if (unlikely(wl->state != WL12XX_STATE_ON))
+ if (unlikely(wl->state != WL1251_STATE_ON))
return;
/* First we read the result */
- wl12xx_spi_mem_read(wl, wl->data_path->tx_complete_addr,
+ wl1251_spi_mem_read(wl, wl->data_path->tx_complete_addr,
result, sizeof(result));
result_index = wl->next_tx_complete;
@@ -459,7 +461,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
if (result_ptr->done_1 == 1 &&
result_ptr->done_2 == 1) {
- wl12xx_tx_packet_cb(wl, result_ptr);
+ wl1251_tx_packet_cb(wl, result_ptr);
result_ptr->done_1 = 0;
result_ptr->done_2 = 0;
@@ -480,7 +482,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
*/
if (result_index > wl->next_tx_complete) {
/* Only 1 write is needed */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr +
(wl->next_tx_complete *
sizeof(struct tx_result)),
@@ -491,7 +493,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
} else if (result_index < wl->next_tx_complete) {
/* 2 writes are needed */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr +
(wl->next_tx_complete *
sizeof(struct tx_result)),
@@ -500,7 +502,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
wl->next_tx_complete) *
sizeof(struct tx_result));
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr,
result,
(num_complete -
@@ -510,7 +512,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
} else {
/* We have to write the whole array */
- wl12xx_spi_mem_write(wl,
+ wl1251_spi_mem_write(wl,
wl->data_path->tx_complete_addr,
result,
FW_TX_CMPLT_BLOCK_SIZE *
@@ -523,7 +525,7 @@ void wl12xx_tx_complete(struct wl12xx *wl)
}
/* caller must hold wl->mutex */
-void wl12xx_tx_flush(struct wl12xx *wl)
+void wl1251_tx_flush(struct wl1251 *wl)
{
int i;
struct sk_buff *skb;
@@ -535,7 +537,7 @@ void wl12xx_tx_flush(struct wl12xx *wl)
while ((skb = skb_dequeue(&wl->tx_queue))) {
info = IEEE80211_SKB_CB(skb);
- wl12xx_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+ wl1251_debug(DEBUG_TX, "flushing skb 0x%p", skb);
if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS))
continue;
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h
index dc82691f4c1..7c1c1665c81 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.h
@@ -1,5 +1,5 @@
/*
- * This file is part of wl12xx
+ * This file is part of wl1251
*
* Copyright (c) 1998-2007 Texas Instruments Incorporated
* Copyright (C) 2008 Nokia Corporation
@@ -22,8 +22,8 @@
*
*/
-#ifndef __WL12XX_TX_H__
-#define __WL12XX_TX_H__
+#ifndef __WL1251_TX_H__
+#define __WL1251_TX_H__
#include <linux/bitops.h>
@@ -73,10 +73,11 @@
#define TX_COMPLETE_REQUIRED_BIT 0x80
#define TX_STATUS_DATA_OUT_COUNT_MASK 0xf
-#define WL12XX_TX_ALIGN_TO 4
-#define WL12XX_TX_ALIGN(len) (((len) + WL12XX_TX_ALIGN_TO - 1) & \
- ~(WL12XX_TX_ALIGN_TO - 1))
-#define WL12XX_TKIP_IV_SPACE 4
+
+#define WL1251_TX_ALIGN_TO 4
+#define WL1251_TX_ALIGN(len) (((len) + WL1251_TX_ALIGN_TO - 1) & \
+ ~(WL1251_TX_ALIGN_TO - 1))
+#define WL1251_TKIP_IV_SPACE 4
struct tx_control {
/* Rate Policy (class) index */
@@ -208,8 +209,8 @@ struct tx_result {
u8 done_2;
} __attribute__ ((packed));
-void wl12xx_tx_work(struct work_struct *work);
-void wl12xx_tx_complete(struct wl12xx *wl);
-void wl12xx_tx_flush(struct wl12xx *wl);
+void wl1251_tx_work(struct work_struct *work);
+void wl1251_tx_complete(struct wl1251 *wl);
+void wl1251_tx_flush(struct wl1251 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
deleted file mode 100644
index 48641437414..00000000000
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * This file is part of wl12xx
- *
- * Copyright (c) 1998-2007 Texas Instruments Incorporated
- * Copyright (C) 2008-2009 Nokia Corporation
- *
- * Contact: Kalle Valo <kalle.valo@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __WL12XX_H__
-#define __WL12XX_H__
-
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <net/mac80211.h>
-
-#define DRIVER_NAME "wl12xx"
-#define DRIVER_PREFIX DRIVER_NAME ": "
-
-enum {
- DEBUG_NONE = 0,
- DEBUG_IRQ = BIT(0),
- DEBUG_SPI = BIT(1),
- DEBUG_BOOT = BIT(2),
- DEBUG_MAILBOX = BIT(3),
- DEBUG_NETLINK = BIT(4),
- DEBUG_EVENT = BIT(5),
- DEBUG_TX = BIT(6),
- DEBUG_RX = BIT(7),
- DEBUG_SCAN = BIT(8),
- DEBUG_CRYPT = BIT(9),
- DEBUG_PSM = BIT(10),
- DEBUG_MAC80211 = BIT(11),
- DEBUG_CMD = BIT(12),
- DEBUG_ACX = BIT(13),
- DEBUG_ALL = ~0,
-};
-
-#define DEBUG_LEVEL (DEBUG_NONE)
-
-#define DEBUG_DUMP_LIMIT 1024
-
-#define wl12xx_error(fmt, arg...) \
- printk(KERN_ERR DRIVER_PREFIX "ERROR " fmt "\n", ##arg)
-
-#define wl12xx_warning(fmt, arg...) \
- printk(KERN_WARNING DRIVER_PREFIX "WARNING " fmt "\n", ##arg)
-
-#define wl12xx_notice(fmt, arg...) \
- printk(KERN_INFO DRIVER_PREFIX fmt "\n", ##arg)
-
-#define wl12xx_info(fmt, arg...) \
- printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg)
-
-#define wl12xx_debug(level, fmt, arg...) \
- do { \
- if (level & DEBUG_LEVEL) \
- printk(KERN_DEBUG DRIVER_PREFIX fmt "\n", ##arg); \
- } while (0)
-
-#define wl12xx_dump(level, prefix, buf, len) \
- do { \
- if (level & DEBUG_LEVEL) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- 0); \
- } while (0)
-
-#define wl12xx_dump_ascii(level, prefix, buf, len) \
- do { \
- if (level & DEBUG_LEVEL) \
- print_hex_dump(KERN_DEBUG, DRIVER_PREFIX prefix, \
- DUMP_PREFIX_OFFSET, 16, 1, \
- buf, \
- min_t(size_t, len, DEBUG_DUMP_LIMIT), \
- true); \
- } while (0)
-
-#define WL12XX_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \
- CFG_BSSID_FILTER_EN)
-
-#define WL12XX_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \
- CFG_RX_MGMT_EN | \
- CFG_RX_DATA_EN | \
- CFG_RX_CTL_EN | \
- CFG_RX_BCN_EN | \
- CFG_RX_AUTH_EN | \
- CFG_RX_ASSOC_EN)
-
-
-struct boot_attr {
- u32 radio_type;
- u8 mac_clock;
- u8 arm_clock;
- int firmware_debug;
- u32 minor;
- u32 major;
- u32 bugfix;
-};
-
-enum wl12xx_state {
- WL12XX_STATE_OFF,
- WL12XX_STATE_ON,
- WL12XX_STATE_PLT,
-};
-
-enum wl12xx_partition_type {
- PART_DOWN,
- PART_WORK,
- PART_DRPW,
-
- PART_TABLE_LEN
-};
-
-struct wl12xx_partition {
- u32 size;
- u32 start;
-};
-
-struct wl12xx_partition_set {
- struct wl12xx_partition mem;
- struct wl12xx_partition reg;
-};
-
-struct wl12xx;
-
-/* FIXME: I'm not sure about this structure name */
-struct wl12xx_chip {
- u32 id;
-
- const char *fw_filename;
- const char *nvs_filename;
-
- char fw_ver[21];
-
- unsigned int power_on_sleep;
- int intr_cmd_complete;
- int intr_init_complete;
-
- int (*op_upload_fw)(struct wl12xx *wl);
- int (*op_upload_nvs)(struct wl12xx *wl);
- int (*op_boot)(struct wl12xx *wl);
- void (*op_set_ecpu_ctrl)(struct wl12xx *wl, u32 flag);
- void (*op_target_enable_interrupts)(struct wl12xx *wl);
- int (*op_hw_init)(struct wl12xx *wl);
- int (*op_plt_init)(struct wl12xx *wl);
-
- struct wl12xx_partition_set *p_table;
- enum wl12xx_acx_int_reg *acx_reg_table;
-};
-
-struct wl12xx_stats {
- struct acx_statistics *fw_stats;
- unsigned long fw_stats_update;
-
- unsigned int retry_count;
- unsigned int excessive_retries;
-};
-
-struct wl12xx_debugfs {
- struct dentry *rootdir;
- struct dentry *fw_statistics;
-
- struct dentry *tx_internal_desc_overflow;
-
- struct dentry *rx_out_of_mem;
- struct dentry *rx_hdr_overflow;
- struct dentry *rx_hw_stuck;
- struct dentry *rx_dropped;
- struct dentry *rx_fcs_err;
- struct dentry *rx_xfr_hint_trig;
- struct dentry *rx_path_reset;
- struct dentry *rx_reset_counter;
-
- struct dentry *dma_rx_requested;
- struct dentry *dma_rx_errors;
- struct dentry *dma_tx_requested;
- struct dentry *dma_tx_errors;
-
- struct dentry *isr_cmd_cmplt;
- struct dentry *isr_fiqs;
- struct dentry *isr_rx_headers;
- struct dentry *isr_rx_mem_overflow;
- struct dentry *isr_rx_rdys;
- struct dentry *isr_irqs;
- struct dentry *isr_tx_procs;
- struct dentry *isr_decrypt_done;
- struct dentry *isr_dma0_done;
- struct dentry *isr_dma1_done;
- struct dentry *isr_tx_exch_complete;
- struct dentry *isr_commands;
- struct dentry *isr_rx_procs;
- struct dentry *isr_hw_pm_mode_changes;
- struct dentry *isr_host_acknowledges;
- struct dentry *isr_pci_pm;
- struct dentry *isr_wakeups;
- struct dentry *isr_low_rssi;
-
- struct dentry *wep_addr_key_count;
- struct dentry *wep_default_key_count;
- /* skipping wep.reserved */
- struct dentry *wep_key_not_found;
- struct dentry *wep_decrypt_fail;
- struct dentry *wep_packets;
- struct dentry *wep_interrupt;
-
- struct dentry *pwr_ps_enter;
- struct dentry *pwr_elp_enter;
- struct dentry *pwr_missing_bcns;
- struct dentry *pwr_wake_on_host;
- struct dentry *pwr_wake_on_timer_exp;
- struct dentry *pwr_tx_with_ps;
- struct dentry *pwr_tx_without_ps;
- struct dentry *pwr_rcvd_beacons;
- struct dentry *pwr_power_save_off;
- struct dentry *pwr_enable_ps;
- struct dentry *pwr_disable_ps;
- struct dentry *pwr_fix_tsf_ps;
- /* skipping cont_miss_bcns_spread for now */
- struct dentry *pwr_rcvd_awake_beacons;
-
- struct dentry *mic_rx_pkts;
- struct dentry *mic_calc_failure;
-
- struct dentry *aes_encrypt_fail;
- struct dentry *aes_decrypt_fail;
- struct dentry *aes_encrypt_packets;
- struct dentry *aes_decrypt_packets;
- struct dentry *aes_encrypt_interrupt;
- struct dentry *aes_decrypt_interrupt;
-
- struct dentry *event_heart_beat;
- struct dentry *event_calibration;
- struct dentry *event_rx_mismatch;
- struct dentry *event_rx_mem_empty;
- struct dentry *event_rx_pool;
- struct dentry *event_oom_late;
- struct dentry *event_phy_transmit_error;
- struct dentry *event_tx_stuck;
-
- struct dentry *ps_pspoll_timeouts;
- struct dentry *ps_upsd_timeouts;
- struct dentry *ps_upsd_max_sptime;
- struct dentry *ps_upsd_max_apturn;
- struct dentry *ps_pspoll_max_apturn;
- struct dentry *ps_pspoll_utilization;
- struct dentry *ps_upsd_utilization;
-
- struct dentry *rxpipe_rx_prep_beacon_drop;
- struct dentry *rxpipe_descr_host_int_trig_rx_data;
- struct dentry *rxpipe_beacon_buffer_thres_host_int_trig_rx_data;
- struct dentry *rxpipe_missed_beacon_host_int_trig_rx_data;
- struct dentry *rxpipe_tx_xfr_host_int_trig_rx_data;
-
- struct dentry *tx_queue_len;
-
- struct dentry *retry_count;
- struct dentry *excessive_retries;
-};
-
-struct wl12xx {
- struct ieee80211_hw *hw;
- bool mac80211_registered;
-
- struct spi_device *spi;
-
- void (*set_power)(bool enable);
- int irq;
-
- enum wl12xx_state state;
- struct mutex mutex;
-
- int physical_mem_addr;
- int physical_reg_addr;
- int virtual_mem_addr;
- int virtual_reg_addr;
-
- struct wl12xx_chip chip;
-
- int cmd_box_addr;
- int event_box_addr;
- struct boot_attr boot_attr;
-
- u8 *fw;
- size_t fw_len;
- u8 *nvs;
- size_t nvs_len;
-
- u8 bssid[ETH_ALEN];
- u8 mac_addr[ETH_ALEN];
- u8 bss_type;
- u8 listen_int;
- int channel;
-
- void *target_mem_map;
- struct acx_data_path_params_resp *data_path;
-
- /* Number of TX packets transferred to the FW, modulo 16 */
- u32 data_in_count;
-
- /* Frames scheduled for transmission, not handled yet */
- struct sk_buff_head tx_queue;
- bool tx_queue_stopped;
-
- struct work_struct tx_work;
- struct work_struct filter_work;
-
- /* Pending TX frames */
- struct sk_buff *tx_frames[16];
-
- /*
- * Index pointing to the next TX complete entry
- * in the cyclic XT complete array we get from
- * the FW.
- */
- u32 next_tx_complete;
-
- /* FW Rx counter */
- u32 rx_counter;
-
- /* Rx frames handled */
- u32 rx_handled;
-
- /* Current double buffer */
- u32 rx_current_buffer;
- u32 rx_last_id;
-
- /* The target interrupt mask */
- u32 intr_mask;
- struct work_struct irq_work;
-
- /* The mbox event mask */
- u32 event_mask;
-
- /* Mailbox pointers */
- u32 mbox_ptr[2];
-
- /* Are we currently scanning */
- bool scanning;
-
- /* Our association ID */
- u16 aid;
-
- /* Default key (for WEP) */
- u32 default_key;
-
- unsigned int tx_mgmt_frm_rate;
- unsigned int tx_mgmt_frm_mod;
-
- unsigned int rx_config;
- unsigned int rx_filter;
-
- /* is firmware in elp mode */
- bool elp;
-
- /* we can be in psm, but not in elp, we have to differentiate */
- bool psm;
-
- /* PSM mode requested */
- bool psm_requested;
-
- /* in dBm */
- int power_level;
-
- struct wl12xx_stats stats;
- struct wl12xx_debugfs debugfs;
-};
-
-int wl12xx_plt_start(struct wl12xx *wl);
-int wl12xx_plt_stop(struct wl12xx *wl);
-
-#define DEFAULT_HW_GEN_MODULATION_TYPE CCK_LONG /* Long Preamble */
-#define DEFAULT_HW_GEN_TX_RATE RATE_2MBPS
-#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
-
-#define WL12XX_DEFAULT_POWER_LEVEL 20
-
-#define WL12XX_TX_QUEUE_MAX_LENGTH 20
-
-/* Different chips need different sleep times after power on. WL1271 needs
- * 200ms, WL1251 needs only 10ms. By default we use 200ms, but as soon as we
- * know the chip ID, we change the sleep value in the wl12xx chip structure,
- * so in subsequent power ons, we don't waste more time then needed. */
-#define WL12XX_DEFAULT_POWER_ON_SLEEP 200
-
-#define CHIP_ID_1251_PG10 (0x7010101)
-#define CHIP_ID_1251_PG11 (0x7020101)
-#define CHIP_ID_1251_PG12 (0x7030101)
-#define CHIP_ID_1271_PG10 (0x4030101)
-
-#endif
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index e3e96bb2c24..a83a5621ec4 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1348,7 +1348,6 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (rc) {
++dev->stats.tx_dropped;
netif_stop_queue(dev);
- rc = NETDEV_TX_OK;
} else {
++dev->stats.tx_packets;
dev->stats.tx_bytes += skb->len;
@@ -1358,7 +1357,7 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&this->lock, flags);
- return rc;
+ return NETDEV_TX_OK;
}
static int wl3501_open(struct net_device *dev)
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 4430b8d92e2..dae1bfb7655 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -789,7 +789,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!zd->mac_enabled || zd->monitor) {
dev->stats.tx_dropped++;
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(dev);
@@ -826,7 +826,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static void zd1201_tx_timeout(struct net_device *dev)
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 40b07b98822..9600b72495d 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -711,7 +711,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
memcpy(skb_put(skb, length), buffer, length);
- ieee80211_rx_irqsafe(hw, skb, &stats);
+ memcpy(IEEE80211_SKB_RXCB(skb), &stats, sizeof(stats));
+ ieee80211_rx_irqsafe(hw, skb);
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 0e6e44689cc..38688847d56 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -36,58 +36,60 @@
static struct usb_device_id usb_ids[] = {
/* ZD1211 */
+ { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0ace, 0xa211), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0df6, 0x9075), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x1435, 0x0711), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3409), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 },
- { USB_DEVICE(0x0105, 0x145f), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
+ { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x054c, 0x0257), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x083a, 0xe501), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe503), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x083a, 0xe506), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0ace, 0xb215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x07fa, 0x1196), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0df6, 0x0036), .driver_info = DEVICE_ZD1211B },
- { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 8d88daeed0c..3700c49d76c 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -558,12 +558,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irq(&np->tx_lock);
- return 0;
+ return NETDEV_TX_OK;
drop:
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static int xennet_close(struct net_device *dev)
diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c
index 5a4ad156f63..0c44135c0b1 100644
--- a/drivers/net/xtsonic.c
+++ b/drivers/net/xtsonic.c
@@ -239,7 +239,7 @@ out:
* Actually probing is superfluous but we're paranoid.
*/
-int __init xtsonic_probe(struct platform_device *pdev)
+int __devinit xtsonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 3c7a5053f1d..c3722b40a65 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -827,7 +827,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb_padto(skb, len)) {
yp->tx_skbuff[entry] = NULL;
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
}
}
@@ -881,7 +881,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Yellowfin transmit frame #%d queued in slot %d.\n",
dev->name, yp->cur_tx, entry);
}
- return 0;
+ return NETDEV_TX_OK;
}
/* The interrupt handler does all of the Rx thread work and cleans up
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 0a6992d8611..7f9e14131a5 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -546,7 +546,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
- return 0;
+ return NETDEV_TX_OK;
length = ETH_ZLEN;
}
@@ -600,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
}
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* The ZNET interrupt handler. */
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 5d610cbcfe8..0f0e0b919ef 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -1134,7 +1134,7 @@ static const struct file_operations ccio_proc_bitmap_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-#endif
+#endif /* CONFIG_PROC_FS */
/**
* ccio_find_ioc - Find the ioc in the ioc_list
@@ -1568,14 +1568,15 @@ static int __init ccio_probe(struct parisc_device *dev)
/* if this fails, no I/O cards will work, so may as well bug */
BUG_ON(dev->dev.platform_data == NULL);
HBA_DATA(dev->dev.platform_data)->iommu = ioc;
-
+
+#ifdef CONFIG_PROC_FS
if (ioc_count == 0) {
proc_create(MODULE_NAME, 0, proc_runway_root,
&ccio_proc_info_fops);
proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root,
&ccio_proc_bitmap_fops);
}
-
+#endif
ioc_count++;
parisc_has_iommu();
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 52ae0b1d470..c590974e981 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -353,7 +353,7 @@ static unsigned int dino_startup_irq(unsigned int irq)
return 0;
}
-static struct hw_interrupt_type dino_interrupt_type = {
+static struct irq_chip dino_interrupt_type = {
.typename = "GSC-PCI",
.startup = dino_startup_irq,
.shutdown = dino_disable_irq,
@@ -1019,22 +1019,22 @@ static int __init dino_probe(struct parisc_device *dev)
** It's not used to avoid chicken/egg problems
** with configuration accessor functions.
*/
- bus = pci_scan_bus_parented(&dev->dev, dino_current_bus,
- &dino_cfg_ops, NULL);
+ dino_dev->hba.hba_bus = bus = pci_scan_bus_parented(&dev->dev,
+ dino_current_bus, &dino_cfg_ops, NULL);
+
if(bus) {
- pci_bus_add_devices(bus);
/* This code *depends* on scanning being single threaded
* if it isn't, this global bus number count will fail
*/
dino_current_bus = bus->subordinate + 1;
pci_bus_assign_resources(bus);
+ pci_bus_add_devices(bus);
} else {
- printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (probably duplicate bus number %d)\n",
+ printk(KERN_ERR "ERROR: failed to scan PCI bus on %s (duplicate bus number %d?)\n",
dev_name(&dev->dev), dino_current_bus);
/* increment the bus number in case of duplicates */
dino_current_bus++;
}
- dino_dev->hba.hba_bus = bus;
return 0;
}
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 5b89f404e66..51220749cb6 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -188,7 +188,7 @@ static unsigned int eisa_startup_irq(unsigned int irq)
return 0;
}
-static struct hw_interrupt_type eisa_interrupt_type = {
+static struct irq_chip eisa_interrupt_type = {
.typename = "EISA",
.startup = eisa_startup_irq,
.shutdown = eisa_disable_irq,
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index d3363291769..647adc9f85a 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -148,7 +148,7 @@ static unsigned int gsc_asic_startup_irq(unsigned int irq)
return 0;
}
-static struct hw_interrupt_type gsc_asic_interrupt_type = {
+static struct irq_chip gsc_asic_interrupt_type = {
.typename = "GSC-ASIC",
.startup = gsc_asic_startup_irq,
.shutdown = gsc_asic_disable_irq,
@@ -158,7 +158,7 @@ static struct hw_interrupt_type gsc_asic_interrupt_type = {
.end = no_end_irq,
};
-int gsc_assign_irq(struct hw_interrupt_type *type, void *data)
+int gsc_assign_irq(struct irq_chip *type, void *data)
{
static int irq = GSC_IRQ_BASE;
struct irq_desc *desc;
diff --git a/drivers/parisc/gsc.h b/drivers/parisc/gsc.h
index 762a1babad6..b9d7bfb68e2 100644
--- a/drivers/parisc/gsc.h
+++ b/drivers/parisc/gsc.h
@@ -38,7 +38,7 @@ struct gsc_asic {
int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic);
int gsc_alloc_irq(struct gsc_irq *dev); /* dev needs an irq */
int gsc_claim_irq(struct gsc_irq *dev, int irq); /* dev needs this irq */
-int gsc_assign_irq(struct hw_interrupt_type *type, void *data);
+int gsc_assign_irq(struct irq_chip *type, void *data);
int gsc_find_local_irq(unsigned int irq, int *global_irq, int limit);
void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl,
void (*choose)(struct parisc_device *child, void *ctrl));
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 4a9cc92d4d1..88e33355321 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -729,7 +729,7 @@ static int iosapic_set_affinity_irq(unsigned int irq,
}
#endif
-static struct hw_interrupt_type iosapic_interrupt_type = {
+static struct irq_chip iosapic_interrupt_type = {
.typename = "IO-SAPIC-level",
.startup = iosapic_startup_irq,
.shutdown = iosapic_disable_irq,
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 59fbbf12836..ede614616f8 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -980,28 +980,38 @@ static void
lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
{
unsigned long bytecnt;
- pdc_pat_cell_mod_maddr_block_t pa_pdc_cell; /* PA_VIEW */
- pdc_pat_cell_mod_maddr_block_t io_pdc_cell; /* IO_VIEW */
long io_count;
long status; /* PDC return status */
long pa_count;
+ pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell; /* PA_VIEW */
+ pdc_pat_cell_mod_maddr_block_t *io_pdc_cell; /* IO_VIEW */
int i;
+ pa_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL);
+ if (!pa_pdc_cell)
+ return;
+
+ io_pdc_cell = kzalloc(sizeof(pdc_pat_cell_mod_maddr_block_t), GFP_KERNEL);
+ if (!pa_pdc_cell) {
+ kfree(pa_pdc_cell);
+ return;
+ }
+
/* return cell module (IO view) */
status = pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
- PA_VIEW, & pa_pdc_cell);
- pa_count = pa_pdc_cell.mod[1];
+ PA_VIEW, pa_pdc_cell);
+ pa_count = pa_pdc_cell->mod[1];
status |= pdc_pat_cell_module(&bytecnt, pa_dev->pcell_loc, pa_dev->mod_index,
- IO_VIEW, &io_pdc_cell);
- io_count = io_pdc_cell.mod[1];
+ IO_VIEW, io_pdc_cell);
+ io_count = io_pdc_cell->mod[1];
/* We've already done this once for device discovery...*/
if (status != PDC_OK) {
panic("pdc_pat_cell_module() call failed for LBA!\n");
}
- if (PAT_GET_ENTITY(pa_pdc_cell.mod_info) != PAT_ENTITY_LBA) {
+ if (PAT_GET_ENTITY(pa_pdc_cell->mod_info) != PAT_ENTITY_LBA) {
panic("pdc_pat_cell_module() entity returned != PAT_ENTITY_LBA!\n");
}
@@ -1016,8 +1026,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
} *p, *io;
struct resource *r;
- p = (void *) &(pa_pdc_cell.mod[2+i*3]);
- io = (void *) &(io_pdc_cell.mod[2+i*3]);
+ p = (void *) &(pa_pdc_cell->mod[2+i*3]);
+ io = (void *) &(io_pdc_cell->mod[2+i*3]);
/* Convert the PAT range data to PCI "struct resource" */
switch(p->type & 0xff) {
@@ -1096,6 +1106,9 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
break;
}
}
+
+ kfree(pa_pdc_cell);
+ kfree(io_pdc_cell);
}
#else
/* keep compiler from complaining about missing declarations */
@@ -1509,10 +1522,6 @@ lba_driver_probe(struct parisc_device *dev)
lba_bus = lba_dev->hba.hba_bus =
pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
cfg_ops, NULL);
- if (lba_bus) {
- lba_next_bus = lba_bus->subordinate + 1;
- pci_bus_add_devices(lba_bus);
- }
/* This is in lieu of calling pci_assign_unassigned_resources() */
if (is_pdc_pat()) {
@@ -1533,7 +1542,6 @@ lba_driver_probe(struct parisc_device *dev)
}
pci_enable_bridges(lba_bus);
-
/*
** Once PCI register ops has walked the bus, access to config
** space is restricted. Avoids master aborts on config cycles.
@@ -1543,6 +1551,11 @@ lba_driver_probe(struct parisc_device *dev)
lba_dev->flags |= LBA_FLAG_SKIP_PROBE;
}
+ if (lba_bus) {
+ lba_next_bus = lba_bus->subordinate + 1;
+ pci_bus_add_devices(lba_bus);
+ }
+
/* Whew! Finally done! Tell services we got this one covered. */
return 0;
}
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index d46dd57450a..123d8fe3427 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -2057,6 +2057,7 @@ void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
r->start = (base & ~1UL) | PCI_F_EXTEND;
size = ~ READ_REG32(reg + LMMIO_DIRECT0_MASK);
r->end = r->start + size;
+ r->flags = IORESOURCE_MEM;
}
}
@@ -2093,4 +2094,5 @@ void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r )
size = (~READ_REG32(sba->sba_hpa + LMMIO_DIST_MASK)) / ROPES_PER_IOC;
r->start += rope * (size + 1); /* adjust base for this rope */
r->end = r->start + size;
+ r->flags = IORESOURCE_MEM;
}
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 33e5ade774c..675f04e6597 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -325,7 +325,7 @@ static unsigned int superio_startup_irq(unsigned int irq)
return 0;
}
-static struct hw_interrupt_type superio_interrupt_type = {
+static struct irq_chip superio_interrupt_type = {
.typename = SUPERIO,
.startup = superio_startup_irq,
.shutdown = superio_disable_irq,
@@ -434,8 +434,8 @@ static void __init superio_parport_init(void)
0 /*base_hi*/,
PAR_IRQ,
PARPORT_DMA_NONE /* dma */,
- NULL /*struct pci_dev* */),
- 0 /* shared irq flags */ )
+ NULL /*struct pci_dev* */,
+ 0 /* shared irq flags */))
printk(KERN_WARNING PFX "Probing parallel port failed.\n");
#endif /* CONFIG_PARPORT_PC */
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 1032d5fdbd4..2597145a066 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2907,6 +2907,7 @@ enum parport_pc_pci_cards {
netmos_9755,
netmos_9805,
netmos_9815,
+ netmos_9901,
quatech_sppxp100,
};
@@ -2987,7 +2988,7 @@ static struct parport_pc_pci {
/* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} },
/* netmos_9805 */ { 1, { { 0, -1 }, } },
/* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } },
-
+ /* netmos_9901 */ { 1, { { 0, -1 }, } },
/* quatech_sppxp100 */ { 1, { { 0, 1 }, } },
};
@@ -3089,6 +3090,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+ 0xA000, 0x2000, 0, 0, netmos_9901 },
/* Quatech SPPXP-100 Parallel port PCI ExpressCard */
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index e53eacd75c8..53075424a43 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -39,7 +39,6 @@
#include <linux/sysdev.h>
#include <asm/cacheflush.h>
#include <asm/iommu.h>
-#include <asm/e820.h>
#include "pci.h"
#define ROOT_SIZE VTD_PAGE_SIZE
@@ -57,14 +56,32 @@
#define MAX_AGAW_WIDTH 64
#define DOMAIN_MAX_ADDR(gaw) ((((u64)1) << gaw) - 1)
+#define DOMAIN_MAX_PFN(gaw) ((((u64)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
-#ifndef PHYSICAL_PAGE_MASK
-#define PHYSICAL_PAGE_MASK PAGE_MASK
-#endif
+
+/* VT-d pages must always be _smaller_ than MM pages. Otherwise things
+ are never going to work. */
+static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
+{
+ return dma_pfn >> (PAGE_SHIFT - VTD_PAGE_SHIFT);
+}
+
+static inline unsigned long mm_to_dma_pfn(unsigned long mm_pfn)
+{
+ return mm_pfn << (PAGE_SHIFT - VTD_PAGE_SHIFT);
+}
+static inline unsigned long page_to_dma_pfn(struct page *pg)
+{
+ return mm_to_dma_pfn(page_to_pfn(pg));
+}
+static inline unsigned long virt_to_dma_pfn(void *p)
+{
+ return page_to_dma_pfn(virt_to_page(p));
+}
/* global iommu list, set NULL for ignored DMAR units */
static struct intel_iommu **g_iommus;
@@ -205,12 +222,17 @@ static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
static inline u64 dma_pte_addr(struct dma_pte *pte)
{
- return (pte->val & VTD_PAGE_MASK);
+#ifdef CONFIG_64BIT
+ return pte->val & VTD_PAGE_MASK;
+#else
+ /* Must have a full atomic 64-bit read */
+ return __cmpxchg64(pte, 0ULL, 0ULL) & VTD_PAGE_MASK;
+#endif
}
-static inline void dma_set_pte_addr(struct dma_pte *pte, u64 addr)
+static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
{
- pte->val |= (addr & VTD_PAGE_MASK);
+ pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
}
static inline bool dma_pte_present(struct dma_pte *pte)
@@ -218,6 +240,11 @@ static inline bool dma_pte_present(struct dma_pte *pte)
return (pte->val & 3) != 0;
}
+static inline int first_pte_in_page(struct dma_pte *pte)
+{
+ return !((unsigned long)pte & ~VTD_PAGE_MASK);
+}
+
/*
* This domain is a statically identity mapping domain.
* 1. This domain creats a static 1:1 mapping to all usable memory.
@@ -245,7 +272,6 @@ struct dmar_domain {
struct iova_domain iovad; /* iova's that belong to this domain */
struct dma_pte *pgd; /* virtual address */
- spinlock_t mapping_lock; /* page table lock */
int gaw; /* max guest address width */
/* adjusted guest address width, 0 is level 2 30-bit */
@@ -649,80 +675,78 @@ static inline int width_to_agaw(int width)
static inline unsigned int level_to_offset_bits(int level)
{
- return (12 + (level - 1) * LEVEL_STRIDE);
+ return (level - 1) * LEVEL_STRIDE;
}
-static inline int address_level_offset(u64 addr, int level)
+static inline int pfn_level_offset(unsigned long pfn, int level)
{
- return ((addr >> level_to_offset_bits(level)) & LEVEL_MASK);
+ return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
}
-static inline u64 level_mask(int level)
+static inline unsigned long level_mask(int level)
{
- return ((u64)-1 << level_to_offset_bits(level));
+ return -1UL << level_to_offset_bits(level);
}
-static inline u64 level_size(int level)
+static inline unsigned long level_size(int level)
{
- return ((u64)1 << level_to_offset_bits(level));
+ return 1UL << level_to_offset_bits(level);
}
-static inline u64 align_to_level(u64 addr, int level)
+static inline unsigned long align_to_level(unsigned long pfn, int level)
{
- return ((addr + level_size(level) - 1) & level_mask(level));
+ return (pfn + level_size(level) - 1) & level_mask(level);
}
-static struct dma_pte * addr_to_dma_pte(struct dmar_domain *domain, u64 addr)
+static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
+ unsigned long pfn)
{
- int addr_width = agaw_to_width(domain->agaw);
+ int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
struct dma_pte *parent, *pte = NULL;
int level = agaw_to_level(domain->agaw);
int offset;
- unsigned long flags;
BUG_ON(!domain->pgd);
-
- addr &= (((u64)1) << addr_width) - 1;
+ BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
parent = domain->pgd;
- spin_lock_irqsave(&domain->mapping_lock, flags);
while (level > 0) {
void *tmp_page;
- offset = address_level_offset(addr, level);
+ offset = pfn_level_offset(pfn, level);
pte = &parent[offset];
if (level == 1)
break;
if (!dma_pte_present(pte)) {
+ uint64_t pteval;
+
tmp_page = alloc_pgtable_page();
- if (!tmp_page) {
- spin_unlock_irqrestore(&domain->mapping_lock,
- flags);
+ if (!tmp_page)
return NULL;
+
+ domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
+ pteval = (virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
+ if (cmpxchg64(&pte->val, 0ULL, pteval)) {
+ /* Someone else set it while we were thinking; use theirs. */
+ free_pgtable_page(tmp_page);
+ } else {
+ dma_pte_addr(pte);
+ domain_flush_cache(domain, pte, sizeof(*pte));
}
- domain_flush_cache(domain, tmp_page, PAGE_SIZE);
- dma_set_pte_addr(pte, virt_to_phys(tmp_page));
- /*
- * high level table always sets r/w, last level page
- * table control read/write
- */
- dma_set_pte_readable(pte);
- dma_set_pte_writable(pte);
- domain_flush_cache(domain, pte, sizeof(*pte));
}
parent = phys_to_virt(dma_pte_addr(pte));
level--;
}
- spin_unlock_irqrestore(&domain->mapping_lock, flags);
return pte;
}
/* return address's pte at specific level */
-static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
- int level)
+static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
+ unsigned long pfn,
+ int level)
{
struct dma_pte *parent, *pte = NULL;
int total = agaw_to_level(domain->agaw);
@@ -730,7 +754,7 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
parent = domain->pgd;
while (level <= total) {
- offset = address_level_offset(addr, total);
+ offset = pfn_level_offset(pfn, total);
pte = &parent[offset];
if (level == total)
return pte;
@@ -743,74 +767,82 @@ static struct dma_pte *dma_addr_level_pte(struct dmar_domain *domain, u64 addr,
return NULL;
}
-/* clear one page's page table */
-static void dma_pte_clear_one(struct dmar_domain *domain, u64 addr)
-{
- struct dma_pte *pte = NULL;
-
- /* get last level pte */
- pte = dma_addr_level_pte(domain, addr, 1);
-
- if (pte) {
- dma_clear_pte(pte);
- domain_flush_cache(domain, pte, sizeof(*pte));
- }
-}
-
/* clear last level pte, a tlb flush should be followed */
-static void dma_pte_clear_range(struct dmar_domain *domain, u64 start, u64 end)
+static void dma_pte_clear_range(struct dmar_domain *domain,
+ unsigned long start_pfn,
+ unsigned long last_pfn)
{
- int addr_width = agaw_to_width(domain->agaw);
- int npages;
+ int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+ struct dma_pte *first_pte, *pte;
+
+ BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
+ BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
- start &= (((u64)1) << addr_width) - 1;
- end &= (((u64)1) << addr_width) - 1;
- /* in case it's partial page */
- start &= PAGE_MASK;
- end = PAGE_ALIGN(end);
- npages = (end - start) / VTD_PAGE_SIZE;
+ /* we don't need lock here; nobody else touches the iova range */
+ while (start_pfn <= last_pfn) {
+ first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
+ if (!pte) {
+ start_pfn = align_to_level(start_pfn + 1, 2);
+ continue;
+ }
+ do {
+ dma_clear_pte(pte);
+ start_pfn++;
+ pte++;
+ } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
- /* we don't need lock here, nobody else touches the iova range */
- while (npages--) {
- dma_pte_clear_one(domain, start);
- start += VTD_PAGE_SIZE;
+ domain_flush_cache(domain, first_pte,
+ (void *)pte - (void *)first_pte);
}
}
/* free page table pages. last level pte should already be cleared */
static void dma_pte_free_pagetable(struct dmar_domain *domain,
- u64 start, u64 end)
+ unsigned long start_pfn,
+ unsigned long last_pfn)
{
- int addr_width = agaw_to_width(domain->agaw);
- struct dma_pte *pte;
+ int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+ struct dma_pte *first_pte, *pte;
int total = agaw_to_level(domain->agaw);
int level;
- u64 tmp;
+ unsigned long tmp;
- start &= (((u64)1) << addr_width) - 1;
- end &= (((u64)1) << addr_width) - 1;
+ BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
+ BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
- /* we don't need lock here, nobody else touches the iova range */
+ /* We don't need lock here; nobody else touches the iova range */
level = 2;
while (level <= total) {
- tmp = align_to_level(start, level);
- if (tmp >= end || (tmp + level_size(level) > end))
+ tmp = align_to_level(start_pfn, level);
+
+ /* If we can't even clear one PTE at this level, we're done */
+ if (tmp + level_size(level) - 1 > last_pfn)
return;
- while (tmp < end) {
- pte = dma_addr_level_pte(domain, tmp, level);
- if (pte) {
- free_pgtable_page(
- phys_to_virt(dma_pte_addr(pte)));
- dma_clear_pte(pte);
- domain_flush_cache(domain, pte, sizeof(*pte));
+ while (tmp + level_size(level) - 1 <= last_pfn) {
+ first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
+ if (!pte) {
+ tmp = align_to_level(tmp + 1, level + 1);
+ continue;
}
- tmp += level_size(level);
+ do {
+ if (dma_pte_present(pte)) {
+ free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
+ dma_clear_pte(pte);
+ }
+ pte++;
+ tmp += level_size(level);
+ } while (!first_pte_in_page(pte) &&
+ tmp + level_size(level) - 1 <= last_pfn);
+
+ domain_flush_cache(domain, first_pte,
+ (void *)pte - (void *)first_pte);
+
}
level++;
}
/* free pgd */
- if (start == 0 && end >= ((((u64)1) << addr_width) - 1)) {
+ if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
free_pgtable_page(domain->pgd);
domain->pgd = NULL;
}
@@ -1036,11 +1068,11 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain,
}
static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
- u64 addr, unsigned int pages)
+ unsigned long pfn, unsigned int pages)
{
unsigned int mask = ilog2(__roundup_pow_of_two(pages));
+ uint64_t addr = (uint64_t)pfn << VTD_PAGE_SHIFT;
- BUG_ON(addr & (~VTD_PAGE_MASK));
BUG_ON(pages == 0);
/*
@@ -1055,7 +1087,12 @@ static void iommu_flush_iotlb_psi(struct intel_iommu *iommu, u16 did,
else
iommu->flush.flush_iotlb(iommu, did, addr, mask,
DMA_TLB_PSI_FLUSH);
- if (did)
+
+ /*
+ * In caching mode, domain ID 0 is reserved for non-present to present
+ * mapping flush. Device IOTLB doesn't need to be flushed in this case.
+ */
+ if (!cap_caching_mode(iommu->cap) || did)
iommu_flush_dev_iotlb(iommu->domains[did], addr, mask);
}
@@ -1280,7 +1317,6 @@ static void dmar_init_reserved_ranges(void)
struct pci_dev *pdev = NULL;
struct iova *iova;
int i;
- u64 addr, size;
init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
@@ -1303,12 +1339,9 @@ static void dmar_init_reserved_ranges(void)
r = &pdev->resource[i];
if (!r->flags || !(r->flags & IORESOURCE_MEM))
continue;
- addr = r->start;
- addr &= PHYSICAL_PAGE_MASK;
- size = r->end - addr;
- size = PAGE_ALIGN(size);
- iova = reserve_iova(&reserved_iova_list, IOVA_PFN(addr),
- IOVA_PFN(size + addr) - 1);
+ iova = reserve_iova(&reserved_iova_list,
+ IOVA_PFN(r->start),
+ IOVA_PFN(r->end));
if (!iova)
printk(KERN_ERR "Reserve iova failed\n");
}
@@ -1342,7 +1375,6 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
unsigned long sagaw;
init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
- spin_lock_init(&domain->mapping_lock);
spin_lock_init(&domain->iommu_lock);
domain_reserve_special_ranges(domain);
@@ -1389,7 +1421,6 @@ static void domain_exit(struct dmar_domain *domain)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
- u64 end;
/* Domain 0 is reserved, so dont process it */
if (!domain)
@@ -1398,14 +1429,12 @@ static void domain_exit(struct dmar_domain *domain)
domain_remove_dev_info(domain);
/* destroy iovas */
put_iova_domain(&domain->iovad);
- end = DOMAIN_MAX_ADDR(domain->gaw);
- end = end & (~PAGE_MASK);
/* clear ptes */
- dma_pte_clear_range(domain, 0, end);
+ dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
/* free page tables */
- dma_pte_free_pagetable(domain, 0, end);
+ dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
for_each_active_iommu(iommu, drhd)
if (test_bit(iommu->seq_id, &domain->iommu_bmp))
@@ -1619,42 +1648,86 @@ static int domain_context_mapped(struct pci_dev *pdev)
tmp->devfn);
}
-static int
-domain_page_mapping(struct dmar_domain *domain, dma_addr_t iova,
- u64 hpa, size_t size, int prot)
+static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+ struct scatterlist *sg, unsigned long phys_pfn,
+ unsigned long nr_pages, int prot)
{
- u64 start_pfn, end_pfn;
- struct dma_pte *pte;
- int index;
- int addr_width = agaw_to_width(domain->agaw);
+ struct dma_pte *first_pte = NULL, *pte = NULL;
+ phys_addr_t uninitialized_var(pteval);
+ int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+ unsigned long sg_res;
- hpa &= (((u64)1) << addr_width) - 1;
+ BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
if ((prot & (DMA_PTE_READ|DMA_PTE_WRITE)) == 0)
return -EINVAL;
- iova &= PAGE_MASK;
- start_pfn = ((u64)hpa) >> VTD_PAGE_SHIFT;
- end_pfn = (VTD_PAGE_ALIGN(((u64)hpa) + size)) >> VTD_PAGE_SHIFT;
- index = 0;
- while (start_pfn < end_pfn) {
- pte = addr_to_dma_pte(domain, iova + VTD_PAGE_SIZE * index);
- if (!pte)
- return -ENOMEM;
+
+ prot &= DMA_PTE_READ | DMA_PTE_WRITE | DMA_PTE_SNP;
+
+ if (sg)
+ sg_res = 0;
+ else {
+ sg_res = nr_pages + 1;
+ pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
+ }
+
+ while (nr_pages--) {
+ uint64_t tmp;
+
+ if (!sg_res) {
+ sg_res = (sg->offset + sg->length + VTD_PAGE_SIZE - 1) >> VTD_PAGE_SHIFT;
+ sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
+ sg->dma_length = sg->length;
+ pteval = page_to_phys(sg_page(sg)) | prot;
+ }
+ if (!pte) {
+ first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
+ if (!pte)
+ return -ENOMEM;
+ }
/* We don't need lock here, nobody else
* touches the iova range
*/
- BUG_ON(dma_pte_addr(pte));
- dma_set_pte_addr(pte, start_pfn << VTD_PAGE_SHIFT);
- dma_set_pte_prot(pte, prot);
- if (prot & DMA_PTE_SNP)
- dma_set_pte_snp(pte);
- domain_flush_cache(domain, pte, sizeof(*pte));
- start_pfn++;
- index++;
+ tmp = cmpxchg64_local(&pte->val, 0ULL, pteval);
+ if (tmp) {
+ static int dumps = 5;
+ printk(KERN_CRIT "ERROR: DMA PTE for vPFN 0x%lx already set (to %llx not %llx)\n",
+ iov_pfn, tmp, (unsigned long long)pteval);
+ if (dumps) {
+ dumps--;
+ debug_dma_dump_mappings(NULL);
+ }
+ WARN_ON(1);
+ }
+ pte++;
+ if (!nr_pages || first_pte_in_page(pte)) {
+ domain_flush_cache(domain, first_pte,
+ (void *)pte - (void *)first_pte);
+ pte = NULL;
+ }
+ iov_pfn++;
+ pteval += VTD_PAGE_SIZE;
+ sg_res--;
+ if (!sg_res)
+ sg = sg_next(sg);
}
return 0;
}
+static inline int domain_sg_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+ struct scatterlist *sg, unsigned long nr_pages,
+ int prot)
+{
+ return __domain_mapping(domain, iov_pfn, sg, 0, nr_pages, prot);
+}
+
+static inline int domain_pfn_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
+ unsigned long phys_pfn, unsigned long nr_pages,
+ int prot)
+{
+ return __domain_mapping(domain, iov_pfn, NULL, phys_pfn, nr_pages, prot);
+}
+
static void iommu_detach_dev(struct intel_iommu *iommu, u8 bus, u8 devfn)
{
if (!iommu)
@@ -1845,58 +1918,61 @@ error:
static int iommu_identity_mapping;
+static int iommu_domain_identity_map(struct dmar_domain *domain,
+ unsigned long long start,
+ unsigned long long end)
+{
+ unsigned long first_vpfn = start >> VTD_PAGE_SHIFT;
+ unsigned long last_vpfn = end >> VTD_PAGE_SHIFT;
+
+ if (!reserve_iova(&domain->iovad, dma_to_mm_pfn(first_vpfn),
+ dma_to_mm_pfn(last_vpfn))) {
+ printk(KERN_ERR "IOMMU: reserve iova failed\n");
+ return -ENOMEM;
+ }
+
+ pr_debug("Mapping reserved region %llx-%llx for domain %d\n",
+ start, end, domain->id);
+ /*
+ * RMRR range might have overlap with physical memory range,
+ * clear it first
+ */
+ dma_pte_clear_range(domain, first_vpfn, last_vpfn);
+
+ return domain_pfn_mapping(domain, first_vpfn, first_vpfn,
+ last_vpfn - first_vpfn + 1,
+ DMA_PTE_READ|DMA_PTE_WRITE);
+}
+
static int iommu_prepare_identity_map(struct pci_dev *pdev,
unsigned long long start,
unsigned long long end)
{
struct dmar_domain *domain;
- unsigned long size;
- unsigned long long base;
int ret;
printk(KERN_INFO
- "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
- pci_name(pdev), start, end);
- if (iommu_identity_mapping)
- domain = si_domain;
- else
- /* page table init */
- domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
+ "IOMMU: Setting identity map for device %s [0x%Lx - 0x%Lx]\n",
+ pci_name(pdev), start, end);
+
+ domain = get_domain_for_dev(pdev, DEFAULT_DOMAIN_ADDRESS_WIDTH);
if (!domain)
return -ENOMEM;
- /* The address might not be aligned */
- base = start & PAGE_MASK;
- size = end - base;
- size = PAGE_ALIGN(size);
- if (!reserve_iova(&domain->iovad, IOVA_PFN(base),
- IOVA_PFN(base + size) - 1)) {
- printk(KERN_ERR "IOMMU: reserve iova failed\n");
- ret = -ENOMEM;
- goto error;
- }
-
- pr_debug("Mapping reserved region %lx@%llx for %s\n",
- size, base, pci_name(pdev));
- /*
- * RMRR range might have overlap with physical memory range,
- * clear it first
- */
- dma_pte_clear_range(domain, base, base + size);
-
- ret = domain_page_mapping(domain, base, base, size,
- DMA_PTE_READ|DMA_PTE_WRITE);
+ ret = iommu_domain_identity_map(domain, start, end);
if (ret)
goto error;
/* context entry init */
ret = domain_context_mapping(domain, pdev, CONTEXT_TT_MULTI_LEVEL);
- if (!ret)
- return 0;
-error:
+ if (ret)
+ goto error;
+
+ return 0;
+
+ error:
domain_exit(domain);
return ret;
-
}
static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
@@ -1908,64 +1984,6 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
rmrr->end_address + 1);
}
-#ifdef CONFIG_DMAR_GFX_WA
-struct iommu_prepare_data {
- struct pci_dev *pdev;
- int ret;
-};
-
-static int __init iommu_prepare_work_fn(unsigned long start_pfn,
- unsigned long end_pfn, void *datax)
-{
- struct iommu_prepare_data *data;
-
- data = (struct iommu_prepare_data *)datax;
-
- data->ret = iommu_prepare_identity_map(data->pdev,
- start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
- return data->ret;
-
-}
-
-static int __init iommu_prepare_with_active_regions(struct pci_dev *pdev)
-{
- int nid;
- struct iommu_prepare_data data;
-
- data.pdev = pdev;
- data.ret = 0;
-
- for_each_online_node(nid) {
- work_with_active_regions(nid, iommu_prepare_work_fn, &data);
- if (data.ret)
- return data.ret;
- }
- return data.ret;
-}
-
-static void __init iommu_prepare_gfx_mapping(void)
-{
- struct pci_dev *pdev = NULL;
- int ret;
-
- for_each_pci_dev(pdev) {
- if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO ||
- !IS_GFX_DEVICE(pdev))
- continue;
- printk(KERN_INFO "IOMMU: gfx device %s 1-1 mapping\n",
- pci_name(pdev));
- ret = iommu_prepare_with_active_regions(pdev);
- if (ret)
- printk(KERN_ERR "IOMMU: mapping reserved region failed\n");
- }
-}
-#else /* !CONFIG_DMAR_GFX_WA */
-static inline void iommu_prepare_gfx_mapping(void)
-{
- return;
-}
-#endif
-
#ifdef CONFIG_DMAR_FLOPPY_WA
static inline void iommu_prepare_isa(void)
{
@@ -1976,12 +1994,12 @@ static inline void iommu_prepare_isa(void)
if (!pdev)
return;
- printk(KERN_INFO "IOMMU: Prepare 0-16M unity mapping for LPC\n");
+ printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
if (ret)
- printk(KERN_ERR "IOMMU: Failed to create 0-64M identity map, "
- "floppy might not work\n");
+ printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
+ "floppy might not work\n");
}
#else
@@ -2009,16 +2027,30 @@ static int __init init_context_pass_through(void)
}
static int md_domain_init(struct dmar_domain *domain, int guest_width);
+
+static int __init si_domain_work_fn(unsigned long start_pfn,
+ unsigned long end_pfn, void *datax)
+{
+ int *ret = datax;
+
+ *ret = iommu_domain_identity_map(si_domain,
+ (uint64_t)start_pfn << PAGE_SHIFT,
+ (uint64_t)end_pfn << PAGE_SHIFT);
+ return *ret;
+
+}
+
static int si_domain_init(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
- int ret = 0;
+ int nid, ret = 0;
si_domain = alloc_domain();
if (!si_domain)
return -EFAULT;
+ pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
for_each_active_iommu(iommu, drhd) {
ret = iommu_attach_domain(si_domain, iommu);
@@ -2035,6 +2067,12 @@ static int si_domain_init(void)
si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
+ for_each_online_node(nid) {
+ work_with_active_regions(nid, si_domain_work_fn, &ret);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -2081,7 +2119,6 @@ static int domain_add_dev_info(struct dmar_domain *domain,
static int iommu_prepare_static_identity_mapping(void)
{
- int i;
struct pci_dev *pdev = NULL;
int ret;
@@ -2089,20 +2126,14 @@ static int iommu_prepare_static_identity_mapping(void)
if (ret)
return -EFAULT;
- printk(KERN_INFO "IOMMU: Setting identity map:\n");
for_each_pci_dev(pdev) {
- for (i = 0; i < e820.nr_map; i++) {
- struct e820entry *ei = &e820.map[i];
-
- if (ei->type == E820_RAM) {
- ret = iommu_prepare_identity_map(pdev,
- ei->addr, ei->addr + ei->size);
- if (ret) {
- printk(KERN_INFO "1:1 mapping to one domain failed.\n");
- return -EFAULT;
- }
- }
- }
+ printk(KERN_INFO "IOMMU: identity mapping for device %s\n",
+ pci_name(pdev));
+
+ ret = domain_context_mapping(si_domain, pdev,
+ CONTEXT_TT_MULTI_LEVEL);
+ if (ret)
+ return ret;
ret = domain_add_dev_info(si_domain, pdev);
if (ret)
return ret;
@@ -2293,8 +2324,6 @@ int __init init_dmars(void)
}
}
- iommu_prepare_gfx_mapping();
-
iommu_prepare_isa();
}
@@ -2339,50 +2368,40 @@ error:
return ret;
}
-static inline u64 aligned_size(u64 host_addr, size_t size)
-{
- u64 addr;
- addr = (host_addr & (~PAGE_MASK)) + size;
- return PAGE_ALIGN(addr);
-}
-
-struct iova *
-iommu_alloc_iova(struct dmar_domain *domain, size_t size, u64 end)
+static inline unsigned long aligned_nrpages(unsigned long host_addr,
+ size_t size)
{
- struct iova *piova;
+ host_addr &= ~PAGE_MASK;
+ host_addr += size + PAGE_SIZE - 1;
- /* Make sure it's in range */
- end = min_t(u64, DOMAIN_MAX_ADDR(domain->gaw), end);
- if (!size || (IOVA_START_ADDR + size > end))
- return NULL;
-
- piova = alloc_iova(&domain->iovad,
- size >> PAGE_SHIFT, IOVA_PFN(end), 1);
- return piova;
+ return host_addr >> VTD_PAGE_SHIFT;
}
-static struct iova *
-__intel_alloc_iova(struct device *dev, struct dmar_domain *domain,
- size_t size, u64 dma_mask)
+static struct iova *intel_alloc_iova(struct device *dev,
+ struct dmar_domain *domain,
+ unsigned long nrpages, uint64_t dma_mask)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct iova *iova = NULL;
- if (dma_mask <= DMA_BIT_MASK(32) || dmar_forcedac)
- iova = iommu_alloc_iova(domain, size, dma_mask);
- else {
+ /* Restrict dma_mask to the width that the iommu can handle */
+ dma_mask = min_t(uint64_t, DOMAIN_MAX_ADDR(domain->gaw), dma_mask);
+
+ if (!dmar_forcedac && dma_mask > DMA_BIT_MASK(32)) {
/*
* First try to allocate an io virtual address in
* DMA_BIT_MASK(32) and if that fails then try allocating
* from higher range
*/
- iova = iommu_alloc_iova(domain, size, DMA_BIT_MASK(32));
- if (!iova)
- iova = iommu_alloc_iova(domain, size, dma_mask);
- }
-
- if (!iova) {
- printk(KERN_ERR"Allocating iova for %s failed", pci_name(pdev));
+ iova = alloc_iova(&domain->iovad, nrpages,
+ IOVA_PFN(DMA_BIT_MASK(32)), 1);
+ if (iova)
+ return iova;
+ }
+ iova = alloc_iova(&domain->iovad, nrpages, IOVA_PFN(dma_mask), 1);
+ if (unlikely(!iova)) {
+ printk(KERN_ERR "Allocating %ld-page iova for %s failed",
+ nrpages, pci_name(pdev));
return NULL;
}
@@ -2485,14 +2504,12 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
return 0;
iommu = domain_get_iommu(domain);
- size = aligned_size((u64)paddr, size);
+ size = aligned_nrpages(paddr, size);
- iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
+ iova = intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
if (!iova)
goto error;
- start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
-
/*
* Check if DMAR supports zero-length reads on write only
* mappings..
@@ -2508,20 +2525,20 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
* might have two guest_addr mapping to the same host paddr, but this
* is not a big problem
*/
- ret = domain_page_mapping(domain, start_paddr,
- ((u64)paddr) & PHYSICAL_PAGE_MASK,
- size, prot);
+ ret = domain_pfn_mapping(domain, mm_to_dma_pfn(iova->pfn_lo),
+ paddr >> VTD_PAGE_SHIFT, size, prot);
if (ret)
goto error;
/* it's a non-present to present mapping. Only flush if caching mode */
if (cap_caching_mode(iommu->cap))
- iommu_flush_iotlb_psi(iommu, 0, start_paddr,
- size >> VTD_PAGE_SHIFT);
+ iommu_flush_iotlb_psi(iommu, 0, mm_to_dma_pfn(iova->pfn_lo), size);
else
iommu_flush_write_buffer(iommu);
- return start_paddr + ((u64)paddr & (~PAGE_MASK));
+ start_paddr = (phys_addr_t)iova->pfn_lo << PAGE_SHIFT;
+ start_paddr += paddr & ~PAGE_MASK;
+ return start_paddr;
error:
if (iova)
@@ -2614,7 +2631,7 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
{
struct pci_dev *pdev = to_pci_dev(dev);
struct dmar_domain *domain;
- unsigned long start_addr;
+ unsigned long start_pfn, last_pfn;
struct iova *iova;
struct intel_iommu *iommu;
@@ -2627,22 +2644,25 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr,
iommu = domain_get_iommu(domain);
iova = find_iova(&domain->iovad, IOVA_PFN(dev_addr));
- if (!iova)
+ if (WARN_ONCE(!iova, "Driver unmaps unmatched page at PFN %llx\n",
+ (unsigned long long)dev_addr))
return;
- start_addr = iova->pfn_lo << PAGE_SHIFT;
- size = aligned_size((u64)dev_addr, size);
+ start_pfn = mm_to_dma_pfn(iova->pfn_lo);
+ last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
- pr_debug("Device %s unmapping: %zx@%llx\n",
- pci_name(pdev), size, (unsigned long long)start_addr);
+ pr_debug("Device %s unmapping: pfn %lx-%lx\n",
+ pci_name(pdev), start_pfn, last_pfn);
/* clear the whole page */
- dma_pte_clear_range(domain, start_addr, start_addr + size);
+ dma_pte_clear_range(domain, start_pfn, last_pfn);
+
/* free page tables */
- dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+ dma_pte_free_pagetable(domain, start_pfn, last_pfn);
+
if (intel_iommu_strict) {
- iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
- size >> VTD_PAGE_SHIFT);
+ iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
+ last_pfn - start_pfn + 1);
/* free iova */
__free_iova(&domain->iovad, iova);
} else {
@@ -2700,14 +2720,10 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
int nelems, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
- int i;
struct pci_dev *pdev = to_pci_dev(hwdev);
struct dmar_domain *domain;
- unsigned long start_addr;
+ unsigned long start_pfn, last_pfn;
struct iova *iova;
- size_t size = 0;
- phys_addr_t addr;
- struct scatterlist *sg;
struct intel_iommu *iommu;
if (iommu_no_mapping(pdev))
@@ -2719,22 +2735,21 @@ static void intel_unmap_sg(struct device *hwdev, struct scatterlist *sglist,
iommu = domain_get_iommu(domain);
iova = find_iova(&domain->iovad, IOVA_PFN(sglist[0].dma_address));
- if (!iova)
+ if (WARN_ONCE(!iova, "Driver unmaps unmatched sglist at PFN %llx\n",
+ (unsigned long long)sglist[0].dma_address))
return;
- for_each_sg(sglist, sg, nelems, i) {
- addr = page_to_phys(sg_page(sg)) + sg->offset;
- size += aligned_size((u64)addr, sg->length);
- }
- start_addr = iova->pfn_lo << PAGE_SHIFT;
+ start_pfn = mm_to_dma_pfn(iova->pfn_lo);
+ last_pfn = mm_to_dma_pfn(iova->pfn_hi + 1) - 1;
/* clear the whole page */
- dma_pte_clear_range(domain, start_addr, start_addr + size);
+ dma_pte_clear_range(domain, start_pfn, last_pfn);
+
/* free page tables */
- dma_pte_free_pagetable(domain, start_addr, start_addr + size);
+ dma_pte_free_pagetable(domain, start_pfn, last_pfn);
- iommu_flush_iotlb_psi(iommu, domain->id, start_addr,
- size >> VTD_PAGE_SHIFT);
+ iommu_flush_iotlb_psi(iommu, domain->id, start_pfn,
+ (last_pfn - start_pfn + 1));
/* free iova */
__free_iova(&domain->iovad, iova);
@@ -2757,17 +2772,16 @@ static int intel_nontranslate_map_sg(struct device *hddev,
static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int nelems,
enum dma_data_direction dir, struct dma_attrs *attrs)
{
- phys_addr_t addr;
int i;
struct pci_dev *pdev = to_pci_dev(hwdev);
struct dmar_domain *domain;
size_t size = 0;
int prot = 0;
- size_t offset = 0;
+ size_t offset_pfn = 0;
struct iova *iova = NULL;
int ret;
struct scatterlist *sg;
- unsigned long start_addr;
+ unsigned long start_vpfn;
struct intel_iommu *iommu;
BUG_ON(dir == DMA_NONE);
@@ -2780,12 +2794,10 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
iommu = domain_get_iommu(domain);
- for_each_sg(sglist, sg, nelems, i) {
- addr = page_to_phys(sg_page(sg)) + sg->offset;
- size += aligned_size((u64)addr, sg->length);
- }
+ for_each_sg(sglist, sg, nelems, i)
+ size += aligned_nrpages(sg->offset, sg->length);
- iova = __intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
+ iova = intel_alloc_iova(hwdev, domain, size, pdev->dma_mask);
if (!iova) {
sglist->dma_length = 0;
return 0;
@@ -2801,35 +2813,24 @@ static int intel_map_sg(struct device *hwdev, struct scatterlist *sglist, int ne
if (dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL)
prot |= DMA_PTE_WRITE;
- start_addr = iova->pfn_lo << PAGE_SHIFT;
- offset = 0;
- for_each_sg(sglist, sg, nelems, i) {
- addr = page_to_phys(sg_page(sg)) + sg->offset;
- size = aligned_size((u64)addr, sg->length);
- ret = domain_page_mapping(domain, start_addr + offset,
- ((u64)addr) & PHYSICAL_PAGE_MASK,
- size, prot);
- if (ret) {
- /* clear the page */
- dma_pte_clear_range(domain, start_addr,
- start_addr + offset);
- /* free page tables */
- dma_pte_free_pagetable(domain, start_addr,
- start_addr + offset);
- /* free iova */
- __free_iova(&domain->iovad, iova);
- return 0;
- }
- sg->dma_address = start_addr + offset +
- ((u64)addr & (~PAGE_MASK));
- sg->dma_length = sg->length;
- offset += size;
+ start_vpfn = mm_to_dma_pfn(iova->pfn_lo);
+
+ ret = domain_sg_mapping(domain, start_vpfn, sglist, mm_to_dma_pfn(size), prot);
+ if (unlikely(ret)) {
+ /* clear the page */
+ dma_pte_clear_range(domain, start_vpfn,
+ start_vpfn + size - 1);
+ /* free page tables */
+ dma_pte_free_pagetable(domain, start_vpfn,
+ start_vpfn + size - 1);
+ /* free iova */
+ __free_iova(&domain->iovad, iova);
+ return 0;
}
/* it's a non-present to present mapping. Only flush if caching mode */
if (cap_caching_mode(iommu->cap))
- iommu_flush_iotlb_psi(iommu, 0, start_addr,
- offset >> VTD_PAGE_SHIFT);
+ iommu_flush_iotlb_psi(iommu, 0, start_vpfn, offset_pfn);
else
iommu_flush_write_buffer(iommu);
@@ -3334,7 +3335,6 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
int adjust_width;
init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
- spin_lock_init(&domain->mapping_lock);
spin_lock_init(&domain->iommu_lock);
domain_reserve_special_ranges(domain);
@@ -3388,8 +3388,6 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
static void vm_domain_exit(struct dmar_domain *domain)
{
- u64 end;
-
/* Domain 0 is reserved, so dont process it */
if (!domain)
return;
@@ -3397,14 +3395,12 @@ static void vm_domain_exit(struct dmar_domain *domain)
vm_domain_remove_all_dev_info(domain);
/* destroy iovas */
put_iova_domain(&domain->iovad);
- end = DOMAIN_MAX_ADDR(domain->gaw);
- end = end & (~VTD_PAGE_MASK);
/* clear ptes */
- dma_pte_clear_range(domain, 0, end);
+ dma_pte_clear_range(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
/* free page tables */
- dma_pte_free_pagetable(domain, 0, end);
+ dma_pte_free_pagetable(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
iommu_free_vm_domain(domain);
free_domain_mem(domain);
@@ -3513,7 +3509,7 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
if ((iommu_prot & IOMMU_CACHE) && dmar_domain->iommu_snooping)
prot |= DMA_PTE_SNP;
- max_addr = (iova & VTD_PAGE_MASK) + VTD_PAGE_ALIGN(size);
+ max_addr = iova + size;
if (dmar_domain->max_addr < max_addr) {
int min_agaw;
u64 end;
@@ -3531,8 +3527,11 @@ static int intel_iommu_map_range(struct iommu_domain *domain,
}
dmar_domain->max_addr = max_addr;
}
-
- ret = domain_page_mapping(dmar_domain, iova, hpa, size, prot);
+ /* Round up size to next multiple of PAGE_SIZE, if it and
+ the low bits of hpa would take us onto the next page */
+ size = aligned_nrpages(hpa, size);
+ ret = domain_pfn_mapping(dmar_domain, iova >> VTD_PAGE_SHIFT,
+ hpa >> VTD_PAGE_SHIFT, size, prot);
return ret;
}
@@ -3540,15 +3539,12 @@ static void intel_iommu_unmap_range(struct iommu_domain *domain,
unsigned long iova, size_t size)
{
struct dmar_domain *dmar_domain = domain->priv;
- dma_addr_t base;
- /* The address might not be aligned */
- base = iova & VTD_PAGE_MASK;
- size = VTD_PAGE_ALIGN(size);
- dma_pte_clear_range(dmar_domain, base, base + size);
+ dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT,
+ (iova + size - 1) >> VTD_PAGE_SHIFT);
- if (dmar_domain->max_addr == base + size)
- dmar_domain->max_addr = base;
+ if (dmar_domain->max_addr == iova + size)
+ dmar_domain->max_addr = iova;
}
static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
@@ -3558,7 +3554,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
struct dma_pte *pte;
u64 phys = 0;
- pte = addr_to_dma_pte(dmar_domain, iova);
+ pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
if (pte)
phys = dma_pte_addr(pte);
diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c
index 2287116e982..46dd440e231 100644
--- a/drivers/pci/iova.c
+++ b/drivers/pci/iova.c
@@ -1,9 +1,19 @@
/*
- * Copyright (c) 2006, Intel Corporation.
+ * Copyright © 2006-2009, Intel Corporation.
*
- * This file is released under the GPLv2.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
*
- * Copyright (C) 2006-2008 Intel Corporation
* Author: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
*/
@@ -123,7 +133,15 @@ move_left:
/* Insert the new_iova into domain rbtree by holding writer lock */
/* Add new node and rebalance tree. */
{
- struct rb_node **entry = &((prev)), *parent = NULL;
+ struct rb_node **entry, *parent = NULL;
+
+ /* If we have 'prev', it's a valid place to start the
+ insertion. Otherwise, start from the root. */
+ if (prev)
+ entry = &prev;
+ else
+ entry = &iovad->rbroot.rb_node;
+
/* Figure out where to put new node */
while (*entry) {
struct iova *this = container_of(*entry,
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index 659421d0ca4..d4ad50d737b 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -1,7 +1,7 @@
/*
* vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services.
*
- * Copyright (C) 2003-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@linux-mips.org>
*
* 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
@@ -32,7 +32,7 @@
#include "i82365.h"
MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services");
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
MODULE_LICENSE("GPL");
#define CARD_MAX_SLOTS 2
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
index 812f038e9bd..9b3c15827e5 100644
--- a/drivers/pcmcia/vrc4173_cardu.c
+++ b/drivers/pcmcia/vrc4173_cardu.c
@@ -6,7 +6,7 @@
* NEC VRC4173 CARDU driver for Socket Services
* (This device doesn't support CardBus. it is supporting only 16bit PC Card.)
*
- * Copyright 2002,2003 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright 2002,2003 Yoichi Yuasa <yuasa@linux-mips.org>
*
* 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
@@ -41,7 +41,7 @@
#include "vrc4173_cardu.h"
MODULE_DESCRIPTION("NEC VRC4173 CARDU driver for Socket Services");
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
MODULE_LICENSE("GPL");
static int vrc4173_cardu_slots;
diff --git a/drivers/pcmcia/vrc4173_cardu.h b/drivers/pcmcia/vrc4173_cardu.h
index 7d77c74120c..a7d96018ed8 100644
--- a/drivers/pcmcia/vrc4173_cardu.h
+++ b/drivers/pcmcia/vrc4173_cardu.h
@@ -5,7 +5,7 @@
* BRIEF MODULE DESCRIPTION
* Include file for NEC VRC4173 CARDU.
*
- * Copyright 2002 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright 2002 Yoichi Yuasa <yuasa@linux-mips.org>
*
* 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
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 7232fe7104a..46dad12f952 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -355,6 +355,7 @@ config EEEPC_LAPTOP
depends on INPUT
depends on EXPERIMENTAL
depends on RFKILL || RFKILL = n
+ depends on HOTPLUG_PCI
select BACKLIGHT_CLASS_DEVICE
select HWMON
---help---
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 4207b26ff99..ec560f16d72 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -16,6 +16,8 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -31,6 +33,7 @@
#include <linux/input.h>
#include <linux/rfkill.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#define EEEPC_LAPTOP_VERSION "0.1"
@@ -40,11 +43,6 @@
#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
#define EEEPC_HOTK_HID "ASUS010"
-#define EEEPC_LOG EEEPC_HOTK_FILE ": "
-#define EEEPC_ERR KERN_ERR EEEPC_LOG
-#define EEEPC_WARNING KERN_WARNING EEEPC_LOG
-#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG
-#define EEEPC_INFO KERN_INFO EEEPC_LOG
/*
* Definitions for Asus EeePC
@@ -141,8 +139,10 @@ struct eeepc_hotk {
u16 event_count[128]; /* count for each event */
struct input_dev *inputdev;
u16 *keycode_map;
- struct rfkill *eeepc_wlan_rfkill;
- struct rfkill *eeepc_bluetooth_rfkill;
+ struct rfkill *wlan_rfkill;
+ struct rfkill *bluetooth_rfkill;
+ struct rfkill *wwan3g_rfkill;
+ struct hotplug_slot *hotplug_slot;
};
/* The actual device the driver binds to */
@@ -213,6 +213,15 @@ static struct acpi_driver eeepc_hotk_driver = {
},
};
+/* PCI hotplug ops */
+static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
+ .owner = THIS_MODULE,
+ .get_adapter_status = eeepc_get_adapter_status,
+ .get_power_status = eeepc_get_adapter_status,
+};
+
/* The backlight device /sys/class/backlight */
static struct backlight_device *eeepc_backlight_device;
@@ -274,20 +283,20 @@ static int set_acpi(int cm, int value)
if (method == NULL)
return -ENODEV;
if (write_acpi_int(ehotk->handle, method, value, NULL))
- printk(EEEPC_WARNING "Error writing %s\n", method);
+ pr_warning("Error writing %s\n", method);
}
return 0;
}
static int get_acpi(int cm)
{
- int value = -1;
+ int value = -ENODEV;
if ((ehotk->cm_supported & (0x1 << cm))) {
const char *method = cm_getv[cm];
if (method == NULL)
return -ENODEV;
if (read_acpi_int(ehotk->handle, method, &value))
- printk(EEEPC_WARNING "Error reading %s\n", method);
+ pr_warning("Error reading %s\n", method);
}
return value;
}
@@ -359,13 +368,19 @@ static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
rv = parse_arg(buf, count, &value);
if (rv > 0)
- set_acpi(cm, value);
+ value = set_acpi(cm, value);
+ if (value < 0)
+ return value;
return rv;
}
static ssize_t show_sys_acpi(int cm, char *buf)
{
- return sprintf(buf, "%d\n", get_acpi(cm));
+ int value = get_acpi(cm);
+
+ if (value < 0)
+ return value;
+ return sprintf(buf, "%d\n", value);
}
#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
@@ -539,6 +554,28 @@ static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
return -EINVAL;
}
+static void cmsg_quirk(int cm, const char *name)
+{
+ int dummy;
+
+ /* Some BIOSes do not report cm although it is avaliable.
+ Check if cm_getv[cm] works and, if yes, assume cm should be set. */
+ if (!(ehotk->cm_supported & (1 << cm))
+ && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) {
+ pr_info("%s (%x) not reported by BIOS,"
+ " enabling anyway\n", name, 1 << cm);
+ ehotk->cm_supported |= 1 << cm;
+ }
+}
+
+static void cmsg_quirks(void)
+{
+ cmsg_quirk(CM_ASL_LID, "LID");
+ cmsg_quirk(CM_ASL_TYPE, "TYPE");
+ cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER");
+ cmsg_quirk(CM_ASL_TPD, "TPD");
+}
+
static int eeepc_hotk_check(void)
{
const struct key_entry *key;
@@ -551,26 +588,24 @@ static int eeepc_hotk_check(void)
if (ehotk->device->status.present) {
if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
&buffer)) {
- printk(EEEPC_ERR "Hotkey initialization failed\n");
+ pr_err("Hotkey initialization failed\n");
return -ENODEV;
} else {
- printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
- ehotk->init_flag);
+ pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag);
}
/* get control methods supported */
if (read_acpi_int(ehotk->handle, "CMSG"
, &ehotk->cm_supported)) {
- printk(EEEPC_ERR
- "Get control methods supported failed\n");
+ pr_err("Get control methods supported failed\n");
return -ENODEV;
} else {
- printk(EEEPC_INFO
- "Get control methods supported: 0x%x\n",
- ehotk->cm_supported);
+ cmsg_quirks();
+ pr_info("Get control methods supported: 0x%x\n",
+ ehotk->cm_supported);
}
ehotk->inputdev = input_allocate_device();
if (!ehotk->inputdev) {
- printk(EEEPC_INFO "Unable to allocate input device\n");
+ pr_info("Unable to allocate input device\n");
return 0;
}
ehotk->inputdev->name = "Asus EeePC extra buttons";
@@ -589,12 +624,12 @@ static int eeepc_hotk_check(void)
}
result = input_register_device(ehotk->inputdev);
if (result) {
- printk(EEEPC_INFO "Unable to register input device\n");
+ pr_info("Unable to register input device\n");
input_free_device(ehotk->inputdev);
return 0;
}
} else {
- printk(EEEPC_ERR "Hotkey device not present, aborting\n");
+ pr_err("Hotkey device not present, aborting\n");
return -EINVAL;
}
return 0;
@@ -612,6 +647,19 @@ static int notify_brn(void)
return -1;
}
+static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
+ u8 *value)
+{
+ int val = get_acpi(CM_ASL_WLAN);
+
+ if (val == 1 || val == 0)
+ *value = val;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
static void eeepc_rfkill_hotplug(void)
{
struct pci_dev *dev;
@@ -619,7 +667,7 @@ static void eeepc_rfkill_hotplug(void)
bool blocked;
if (!bus) {
- printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
+ pr_warning("Unable to find PCI bus 1?\n");
return;
}
@@ -635,7 +683,7 @@ static void eeepc_rfkill_hotplug(void)
if (dev) {
pci_bus_assign_resources(bus);
if (pci_bus_add_device(dev))
- printk(EEEPC_ERR "Unable to hotplug wifi\n");
+ pr_err("Unable to hotplug wifi\n");
}
} else {
dev = pci_get_slot(bus, 0);
@@ -645,7 +693,7 @@ static void eeepc_rfkill_hotplug(void)
}
}
- rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
+ rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
}
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
@@ -718,8 +766,7 @@ static int eeepc_register_rfkill_notifier(char *node)
eeepc_rfkill_notify,
NULL);
if (ACPI_FAILURE(status))
- printk(EEEPC_WARNING
- "Failed to register notify on %s\n", node);
+ pr_warning("Failed to register notify on %s\n", node);
} else
return -ENODEV;
@@ -738,19 +785,66 @@ static void eeepc_unregister_rfkill_notifier(char *node)
ACPI_SYSTEM_NOTIFY,
eeepc_rfkill_notify);
if (ACPI_FAILURE(status))
- printk(EEEPC_ERR
- "Error removing rfkill notify handler %s\n",
+ pr_err("Error removing rfkill notify handler %s\n",
node);
}
}
+static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
+{
+ kfree(hotplug_slot->info);
+ kfree(hotplug_slot);
+}
+
+static int eeepc_setup_pci_hotplug(void)
+{
+ int ret = -ENOMEM;
+ struct pci_bus *bus = pci_find_bus(0, 1);
+
+ if (!bus) {
+ pr_err("Unable to find wifi PCI bus\n");
+ return -ENODEV;
+ }
+
+ ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+ if (!ehotk->hotplug_slot)
+ goto error_slot;
+
+ ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
+ GFP_KERNEL);
+ if (!ehotk->hotplug_slot->info)
+ goto error_info;
+
+ ehotk->hotplug_slot->private = ehotk;
+ ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
+ ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
+ eeepc_get_adapter_status(ehotk->hotplug_slot,
+ &ehotk->hotplug_slot->info->adapter_status);
+
+ ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi");
+ if (ret) {
+ pr_err("Unable to register hotplug slot - %d\n", ret);
+ goto error_register;
+ }
+
+ return 0;
+
+error_register:
+ kfree(ehotk->hotplug_slot->info);
+error_info:
+ kfree(ehotk->hotplug_slot);
+ ehotk->hotplug_slot = NULL;
+error_slot:
+ return ret;
+}
+
static int eeepc_hotk_add(struct acpi_device *device)
{
int result;
if (!device)
return -EINVAL;
- printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
+ pr_notice(EEEPC_HOTK_NAME "\n");
ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
if (!ehotk)
return -ENOMEM;
@@ -764,53 +858,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
if (result)
goto ehotk_fail;
- eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
- eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
-
- if (get_acpi(CM_ASL_WLAN) != -1) {
- ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
- &device->dev,
- RFKILL_TYPE_WLAN,
- &eeepc_rfkill_ops,
- (void *)CM_ASL_WLAN);
-
- if (!ehotk->eeepc_wlan_rfkill)
- goto wlan_fail;
-
- rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill,
- get_acpi(CM_ASL_WLAN) != 1);
- result = rfkill_register(ehotk->eeepc_wlan_rfkill);
- if (result)
- goto wlan_fail;
- }
-
- if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
- ehotk->eeepc_bluetooth_rfkill =
- rfkill_alloc("eeepc-bluetooth",
- &device->dev,
- RFKILL_TYPE_BLUETOOTH,
- &eeepc_rfkill_ops,
- (void *)CM_ASL_BLUETOOTH);
-
- if (!ehotk->eeepc_bluetooth_rfkill)
- goto bluetooth_fail;
-
- rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill,
- get_acpi(CM_ASL_BLUETOOTH) != 1);
- result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
- if (result)
- goto bluetooth_fail;
- }
-
return 0;
- bluetooth_fail:
- rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
- rfkill_unregister(ehotk->eeepc_wlan_rfkill);
- wlan_fail:
- rfkill_destroy(ehotk->eeepc_wlan_rfkill);
- eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
- eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
ehotk_fail:
kfree(ehotk);
ehotk = NULL;
@@ -823,16 +872,13 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
- eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
-
kfree(ehotk);
return 0;
}
static int eeepc_hotk_resume(struct acpi_device *device)
{
- if (ehotk->eeepc_wlan_rfkill) {
+ if (ehotk->wlan_rfkill) {
bool wlan;
/* Workaround - it seems that _PTS disables the wireless
@@ -844,14 +890,13 @@ static int eeepc_hotk_resume(struct acpi_device *device)
wlan = get_acpi(CM_ASL_WLAN);
set_acpi(CM_ASL_WLAN, wlan);
- rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
- wlan != 1);
+ rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1);
eeepc_rfkill_hotplug();
}
- if (ehotk->eeepc_bluetooth_rfkill)
- rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
+ if (ehotk->bluetooth_rfkill)
+ rfkill_set_sw_state(ehotk->bluetooth_rfkill,
get_acpi(CM_ASL_BLUETOOTH) != 1);
return 0;
@@ -973,10 +1018,16 @@ static void eeepc_backlight_exit(void)
static void eeepc_rfkill_exit(void)
{
- if (ehotk->eeepc_wlan_rfkill)
- rfkill_unregister(ehotk->eeepc_wlan_rfkill);
- if (ehotk->eeepc_bluetooth_rfkill)
- rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
+ eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
+ eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
+ if (ehotk->wlan_rfkill)
+ rfkill_unregister(ehotk->wlan_rfkill);
+ if (ehotk->bluetooth_rfkill)
+ rfkill_unregister(ehotk->bluetooth_rfkill);
+ if (ehotk->wwan3g_rfkill)
+ rfkill_unregister(ehotk->wwan3g_rfkill);
+ if (ehotk->hotplug_slot)
+ pci_hp_deregister(ehotk->hotplug_slot);
}
static void eeepc_input_exit(void)
@@ -1011,6 +1062,75 @@ static void __exit eeepc_laptop_exit(void)
platform_driver_unregister(&platform_driver);
}
+static int eeepc_new_rfkill(struct rfkill **rfkill,
+ const char *name, struct device *dev,
+ enum rfkill_type type, int cm)
+{
+ int result;
+
+ result = get_acpi(cm);
+ if (result < 0)
+ return result;
+
+ *rfkill = rfkill_alloc(name, dev, type,
+ &eeepc_rfkill_ops, (void *)(unsigned long)cm);
+
+ if (!*rfkill)
+ return -EINVAL;
+
+ rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1);
+ result = rfkill_register(*rfkill);
+ if (result) {
+ rfkill_destroy(*rfkill);
+ *rfkill = NULL;
+ return result;
+ }
+ return 0;
+}
+
+
+static int eeepc_rfkill_init(struct device *dev)
+{
+ int result = 0;
+
+ eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
+ eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
+
+ result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
+ "eeepc-wlan", dev,
+ RFKILL_TYPE_WLAN, CM_ASL_WLAN);
+
+ if (result && result != -ENODEV)
+ goto exit;
+
+ result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill,
+ "eeepc-bluetooth", dev,
+ RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH);
+
+ if (result && result != -ENODEV)
+ goto exit;
+
+ result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill,
+ "eeepc-wwan3g", dev,
+ RFKILL_TYPE_WWAN, CM_ASL_3G);
+
+ if (result && result != -ENODEV)
+ goto exit;
+
+ result = eeepc_setup_pci_hotplug();
+ /*
+ * If we get -EBUSY then something else is handling the PCI hotplug -
+ * don't fail in this case
+ */
+ if (result == -EBUSY)
+ result = 0;
+
+exit:
+ if (result && result != -ENODEV)
+ eeepc_rfkill_exit();
+ return result;
+}
+
static int eeepc_backlight_init(struct device *dev)
{
struct backlight_device *bd;
@@ -1018,8 +1138,7 @@ static int eeepc_backlight_init(struct device *dev)
bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
NULL, &eeepcbl_ops);
if (IS_ERR(bd)) {
- printk(EEEPC_ERR
- "Could not register eeepc backlight device\n");
+ pr_err("Could not register eeepc backlight device\n");
eeepc_backlight_device = NULL;
return PTR_ERR(bd);
}
@@ -1038,8 +1157,7 @@ static int eeepc_hwmon_init(struct device *dev)
hwmon = hwmon_device_register(dev);
if (IS_ERR(hwmon)) {
- printk(EEEPC_ERR
- "Could not register eeepc hwmon device\n");
+ pr_err("Could not register eeepc hwmon device\n");
eeepc_hwmon_device = NULL;
return PTR_ERR(hwmon);
}
@@ -1065,19 +1183,6 @@ static int __init eeepc_laptop_init(void)
acpi_bus_unregister_driver(&eeepc_hotk_driver);
return -ENODEV;
}
- dev = acpi_get_physical_device(ehotk->device->handle);
-
- if (!acpi_video_backlight_support()) {
- result = eeepc_backlight_init(dev);
- if (result)
- goto fail_backlight;
- } else
- printk(EEEPC_INFO "Backlight controlled by ACPI video "
- "driver\n");
-
- result = eeepc_hwmon_init(dev);
- if (result)
- goto fail_hwmon;
eeepc_enable_camera();
@@ -1097,7 +1202,33 @@ static int __init eeepc_laptop_init(void)
&platform_attribute_group);
if (result)
goto fail_sysfs;
+
+ dev = &platform_device->dev;
+
+ if (!acpi_video_backlight_support()) {
+ result = eeepc_backlight_init(dev);
+ if (result)
+ goto fail_backlight;
+ } else
+ pr_info("Backlight controlled by ACPI video "
+ "driver\n");
+
+ result = eeepc_hwmon_init(dev);
+ if (result)
+ goto fail_hwmon;
+
+ result = eeepc_rfkill_init(dev);
+ if (result)
+ goto fail_rfkill;
+
return 0;
+fail_rfkill:
+ eeepc_hwmon_exit();
+fail_hwmon:
+ eeepc_backlight_exit();
+fail_backlight:
+ sysfs_remove_group(&platform_device->dev.kobj,
+ &platform_attribute_group);
fail_sysfs:
platform_device_del(platform_device);
fail_platform_device2:
@@ -1105,12 +1236,7 @@ fail_platform_device2:
fail_platform_device1:
platform_driver_unregister(&platform_driver);
fail_platform_driver:
- eeepc_hwmon_exit();
-fail_hwmon:
- eeepc_backlight_exit();
-fail_backlight:
eeepc_input_exit();
- eeepc_rfkill_exit();
return result;
}
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index aafd3e6ebb0..a118eb0f1e6 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -1,8 +1,8 @@
/*
* Blackfin On-Chip Real Time Clock Driver
- * Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789]
+ * Supports BF51x/BF52x/BF53[123]/BF53[467]/BF54x
*
- * Copyright 2004-2008 Analog Devices Inc.
+ * Copyright 2004-2009 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
@@ -363,7 +363,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
struct bfin_rtc *rtc;
struct device *dev = &pdev->dev;
int ret = 0;
- unsigned long timeout;
+ unsigned long timeout = jiffies + HZ;
dev_dbg_stamp(dev);
@@ -374,32 +374,32 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc);
device_init_wakeup(dev, 1);
+ /* Register our RTC with the RTC framework */
+ rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops,
+ THIS_MODULE);
+ if (unlikely(IS_ERR(rtc->rtc_dev))) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto err;
+ }
+
/* Grab the IRQ and init the hardware */
ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, pdev->name, dev);
if (unlikely(ret))
- goto err;
+ goto err_reg;
/* sometimes the bootloader touched things, but the write complete was not
* enabled, so let's just do a quick timeout here since the IRQ will not fire ...
*/
- timeout = jiffies + HZ;
while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)
if (time_after(jiffies, timeout))
break;
bfin_rtc_reset(dev, RTC_ISTAT_WRITE_COMPLETE);
bfin_write_RTC_SWCNT(0);
- /* Register our RTC with the RTC framework */
- rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops, THIS_MODULE);
- if (unlikely(IS_ERR(rtc->rtc_dev))) {
- ret = PTR_ERR(rtc->rtc_dev);
- goto err_irq;
- }
-
return 0;
- err_irq:
- free_irq(IRQ_RTC, dev);
- err:
+err_reg:
+ rtc_device_unregister(rtc->rtc_dev);
+err:
kfree(rtc);
return ret;
}
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index f11297aff85..2c839d0d21b 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -1,7 +1,7 @@
/*
* Driver for NEC VR4100 series Real Time Clock unit.
*
- * Copyright (C) 2003-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2003-2008 Yoichi Yuasa <yuasa@linux-mips.org>
*
* 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
@@ -33,7 +33,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index f370f8d460a..c63babefb69 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -350,6 +350,8 @@ claw_tx(struct sk_buff *skb, struct net_device *dev)
CLAW_DBF_TEXT_(4, trace, "clawtx%d", rc);
if (rc)
rc = NETDEV_TX_BUSY;
+ else
+ rc = NETDEV_TX_OK;
return rc;
} /* end of claw_tx */
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 222e4739443..38b5079f159 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -880,7 +880,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
"%s(%s): NULL sk_buff passed",
CTCM_FUNTAIL, dev->name);
priv->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) {
CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR,
@@ -888,7 +888,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
CTCM_FUNTAIL, dev->name, LL_HEADER_LENGTH + 2);
dev_kfree_skb(skb);
priv->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/*
@@ -901,7 +901,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
priv->stats.tx_dropped++;
priv->stats.tx_errors++;
priv->stats.tx_carrier_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
if (ctcm_test_and_set_busy(dev))
@@ -910,7 +910,7 @@ static int ctcm_tx(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
if (ctcm_transmit_skb(priv->channel[WRITE], skb) != 0)
return NETDEV_TX_BUSY;
- return 0;
+ return NETDEV_TX_OK;
}
/* unmerged MPC variant of ctcm_tx */
@@ -1008,7 +1008,7 @@ done:
if (do_debug)
MPC_DBF_DEV_NAME(TRACE, dev, "exit");
- return 0; /* handle freeing of skb here */
+ return NETDEV_TX_OK; /* handle freeing of skb here */
}
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 8c675905448..a70de9b4bf2 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1553,24 +1553,24 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb,
struct net_device *dev)
{
struct lcs_header *header;
- int rc = 0;
+ int rc = NETDEV_TX_OK;
LCS_DBF_TEXT(5, trace, "hardxmit");
if (skb == NULL) {
card->stats.tx_dropped++;
card->stats.tx_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
if (card->state != DEV_STATE_UP) {
dev_kfree_skb(skb);
card->stats.tx_dropped++;
card->stats.tx_errors++;
card->stats.tx_carrier_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb->protocol == htons(ETH_P_IPV6)) {
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
netif_stop_queue(card->dev);
spin_lock(&card->lock);
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 8c36eafcfbf..bb1183a2ed6 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1376,14 +1376,14 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
if (skb == NULL) {
IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n");
privptr->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
if (skb_headroom(skb) < NETIUCV_HDRLEN) {
IUCV_DBF_TEXT(data, 2,
"netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n");
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
- return 0;
+ return NETDEV_TX_OK;
}
/**
@@ -1395,7 +1395,7 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
privptr->stats.tx_dropped++;
privptr->stats.tx_errors++;
privptr->stats.tx_carrier_errors++;
- return 0;
+ return NETDEV_TX_OK;
}
if (netiucv_test_and_set_busy(dev)) {
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 691cecd03b8..2cfc338c462 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -744,6 +744,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->stats.tx_bytes += tx_bytes;
if (new_skb != skb)
dev_kfree_skb_any(skb);
+ rc = NETDEV_TX_OK;
} else {
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 54872406864..048defaea81 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -2793,6 +2793,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->perf_stats.sg_frags_sent += nr_frags + 1;
}
}
+ rc = NETDEV_TX_OK;
} else {
if (data_offset >= 0)
kmem_cache_free(qeth_core_header_cache, hdr);
diff --git a/drivers/scsi/cxgb3i/Kbuild b/drivers/scsi/cxgb3i/Kbuild
index 25a2032bfa2..70d060b7ff4 100644
--- a/drivers/scsi/cxgb3i/Kbuild
+++ b/drivers/scsi/cxgb3i/Kbuild
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3
+EXTRA_CFLAGS += -I$(srctree)/drivers/net/cxgb3
cxgb3i-y := cxgb3i_init.o cxgb3i_iscsi.o cxgb3i_pdu.o cxgb3i_offload.o cxgb3i_ddp.o
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index 74369a3f963..c399f485aa7 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -13,6 +13,7 @@
#include <linux/inet.h>
#include <linux/crypto.h>
+#include <linux/if_vlan.h>
#include <net/dst.h>
#include <net/tcp.h>
#include <scsi/scsi_cmnd.h>
@@ -184,6 +185,9 @@ static struct cxgb3i_hba *cxgb3i_hba_find_by_netdev(struct net_device *ndev)
struct cxgb3i_adapter *snic;
int i;
+ if (ndev->priv_flags & IFF_802_1Q_VLAN)
+ ndev = vlan_dev_real_dev(ndev);
+
read_lock(&cxgb3i_snic_rwlock);
list_for_each_entry(snic, &cxgb3i_snic_list, list_head) {
for (i = 0; i < snic->hba_cnt; i++) {
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index a84072865fc..2c266c01dc5 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -473,16 +473,16 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
* limitation for the device. Try 40-bit first, and
* fail to 32-bit.
*/
- err = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(40));
if (err) {
- err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
shost_printk(KERN_ERR, fnic->lport->host,
"No usable DMA configuration "
"aborting\n");
goto err_out_release_regions;
}
- err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
shost_printk(KERN_ERR, fnic->lport->host,
"Unable to obtain 32-bit DMA "
@@ -490,7 +490,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
goto err_out_release_regions;
}
} else {
- err = pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK);
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
if (err) {
shost_printk(KERN_ERR, fnic->lport->host,
"Unable to obtain 40-bit DMA "
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index eabf3650285..bfc996971b8 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -245,7 +245,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
struct vnic_wq_copy *wq,
struct fnic_io_req *io_req,
struct scsi_cmnd *sc,
- u32 sg_count)
+ int sg_count)
{
struct scatterlist *sg;
struct fc_rport *rport = starget_to_rport(scsi_target(sc->device));
@@ -260,9 +260,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
char msg[2];
if (sg_count) {
- BUG_ON(sg_count < 0);
- BUG_ON(sg_count > FNIC_MAX_SG_DESC_CNT);
-
/* For each SGE, create a device desc entry */
desc = io_req->sgl_list;
for_each_sg(scsi_sglist(sc), sg, sg_count, i) {
@@ -344,7 +341,7 @@ int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
struct fnic *fnic;
struct vnic_wq_copy *wq;
int ret;
- u32 sg_count;
+ int sg_count;
unsigned long flags;
unsigned long ptr;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 869a11bdccb..9928704e235 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1095,9 +1095,14 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
MAX_INDIRECT_BUFS);
hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
}
+
+ if (hostdata->madapter_info.os_type == 3) {
+ enable_fast_fail(hostdata);
+ return;
+ }
}
- enable_fast_fail(hostdata);
+ send_srp_login(hostdata);
}
/**
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 2eee9e6e4fe..292c02f810d 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -3670,13 +3670,14 @@ static void
fc_bsg_goose_queue(struct fc_rport *rport)
{
int flagset;
+ unsigned long flags;
if (!rport->rqst_q)
return;
get_device(&rport->dev);
- spin_lock(rport->rqst_q->queue_lock);
+ spin_lock_irqsave(rport->rqst_q->queue_lock, flags);
flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) &&
!test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags);
if (flagset)
@@ -3684,7 +3685,7 @@ fc_bsg_goose_queue(struct fc_rport *rport)
__blk_run_queue(rport->rqst_q);
if (flagset)
queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q);
- spin_unlock(rport->rqst_q->queue_lock);
+ spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags);
put_device(&rport->dev);
}
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 8201387b4da..ef142fd47a8 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -210,13 +210,11 @@ static void sg_put_dev(Sg_device *sdp);
static int sg_allow_access(struct file *filp, unsigned char *cmd)
{
struct sg_fd *sfp = (struct sg_fd *)filp->private_data;
- struct request_queue *q = sfp->parentdp->device->request_queue;
if (sfp->parentdp->device->type == TYPE_SCANNER)
return 0;
- return blk_verify_command(&q->cmd_filter,
- cmd, filp->f_mode & FMODE_WRITE);
+ return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE);
}
static int
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
index 97f3158fa7b..27e84e4b1fa 100644
--- a/drivers/scsi/zalon.c
+++ b/drivers/scsi/zalon.c
@@ -134,7 +134,7 @@ zalon_probe(struct parisc_device *dev)
host = ncr_attach(&zalon7xx_template, unit, &device);
if (!host)
- goto fail;
+ return -ENODEV;
if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) {
dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ",
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index a07015d646d..6160e03f410 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -759,6 +759,8 @@ static int pci_netmos_init(struct pci_dev *dev)
/* subdevice 0x00PS means <P> parallel, <S> serial */
unsigned int num_serial = dev->subsystem_device & 0xf;
+ if (dev->device == PCI_DEVICE_ID_NETMOS_9901)
+ return 0;
if (dev->subsystem_vendor == PCI_VENDOR_ID_IBM &&
dev->subsystem_device == 0x0299)
return 0;
@@ -3557,6 +3559,10 @@ static struct pci_device_id serial_pci_tbl[] = {
PCI_VENDOR_ID_IBM, 0x0299,
0, 0, pbn_b0_bt_2_115200 },
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901,
+ 0xA000, 0x1000,
+ 0, 0, pbn_b0_1_115200 },
+
/*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index 0573f3b5175..dac550e57c2 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -1,7 +1,7 @@
/*
* Driver for NEC VR4100 series Serial Interface Unit.
*
- * Copyright (C) 2004-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2004-2008 Yoichi Yuasa <yuasa@linux-mips.org>
*
* Based on drivers/serial/8250.c, by Russell King.
*
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
index aa90ddb3706..8980a5640bd 100644
--- a/drivers/spi/omap_uwire.c
+++ b/drivers/spi/omap_uwire.c
@@ -514,6 +514,8 @@ static int __init uwire_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+
master->bus_num = 2; /* "official" */
master->num_chipselect = 4;
master->setup = uwire_setup;
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index 2a5abc08e85..f1db395dd88 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -258,6 +258,11 @@ static void bitbang_work(struct work_struct *work)
struct spi_bitbang *bitbang =
container_of(work, struct spi_bitbang, work);
unsigned long flags;
+ int do_setup = -1;
+ int (*setup_transfer)(struct spi_device *,
+ struct spi_transfer *);
+
+ setup_transfer = bitbang->setup_transfer;
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1;
@@ -269,8 +274,6 @@ static void bitbang_work(struct work_struct *work)
unsigned tmp;
unsigned cs_change;
int status;
- int (*setup_transfer)(struct spi_device *,
- struct spi_transfer *);
m = container_of(bitbang->queue.next, struct spi_message,
queue);
@@ -287,19 +290,19 @@ static void bitbang_work(struct work_struct *work)
tmp = 0;
cs_change = 1;
status = 0;
- setup_transfer = NULL;
list_for_each_entry (t, &m->transfers, transfer_list) {
- /* override or restore speed and wordsize */
- if (t->speed_hz || t->bits_per_word) {
- setup_transfer = bitbang->setup_transfer;
+ /* override speed or wordsize? */
+ if (t->speed_hz || t->bits_per_word)
+ do_setup = 1;
+
+ /* init (-1) or override (1) transfer params */
+ if (do_setup != 0) {
if (!setup_transfer) {
status = -ENOPROTOOPT;
break;
}
- }
- if (setup_transfer) {
status = setup_transfer(spi, t);
if (status < 0)
break;
@@ -363,9 +366,10 @@ static void bitbang_work(struct work_struct *work)
m->status = status;
m->complete(m->context);
- /* restore speed and wordsize */
- if (setup_transfer)
+ /* restore speed and wordsize if it was overridden */
+ if (do_setup == 1)
setup_transfer(spi, NULL);
+ do_setup = 0;
/* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 5d869c4d3eb..606e7a40a8d 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -58,15 +58,20 @@ static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
/* Bit masks for spi_device.mode management. Note that incorrect
- * settings for CS_HIGH and 3WIRE can cause *lots* of trouble for other
- * devices on a shared bus: CS_HIGH, because this device will be
- * active when it shouldn't be; 3WIRE, because when active it won't
- * behave as it should.
+ * settings for some settings can cause *lots* of trouble for other
+ * devices on a shared bus:
*
- * REVISIT should changing those two modes be privileged?
+ * - CS_HIGH ... this device will be active when it shouldn't be
+ * - 3WIRE ... when active, it won't behave as it should
+ * - NO_CS ... there will be no explicit message boundaries; this
+ * is completely incompatible with the shared bus model
+ * - READY ... transfers may proceed when they shouldn't.
+ *
+ * REVISIT should changing those flags be privileged?
*/
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
- | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
+ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
+ | SPI_NO_CS | SPI_READY)
struct spidev_data {
dev_t devt;
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
index 3fd3e3b412b..3c6feed46f6 100644
--- a/drivers/ssb/driver_mipscore.c
+++ b/drivers/ssb/driver_mipscore.c
@@ -49,29 +49,54 @@ static const u32 ipsflag_irq_shift[] = {
static inline u32 ssb_irqflag(struct ssb_device *dev)
{
- return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+ u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
+ if (tpsflag)
+ return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+ else
+ /* not irq supported */
+ return 0x3f;
+}
+
+static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
+{
+ struct ssb_bus *bus = rdev->bus;
+ int i;
+ for (i = 0; i < bus->nr_devices; i++) {
+ struct ssb_device *dev;
+ dev = &(bus->devices[i]);
+ if (ssb_irqflag(dev) == irqflag)
+ return dev;
+ }
+ return NULL;
}
/* Get the MIPS IRQ assignment for a specified device.
* If unassigned, 0 is returned.
+ * If disabled, 5 is returned.
+ * If not supported, 6 is returned.
*/
unsigned int ssb_mips_irq(struct ssb_device *dev)
{
struct ssb_bus *bus = dev->bus;
+ struct ssb_device *mdev = bus->mipscore.dev;
u32 irqflag;
u32 ipsflag;
u32 tmp;
unsigned int irq;
irqflag = ssb_irqflag(dev);
+ if (irqflag == 0x3f)
+ return 6;
ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
for (irq = 1; irq <= 4; irq++) {
tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
if (tmp == irqflag)
break;
}
- if (irq == 5)
- irq = 0;
+ if (irq == 5) {
+ if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
+ irq = 0;
+ }
return irq;
}
@@ -97,25 +122,56 @@ static void set_irq(struct ssb_device *dev, unsigned int irq)
struct ssb_device *mdev = bus->mipscore.dev;
u32 irqflag = ssb_irqflag(dev);
+ BUG_ON(oldirq == 6);
+
dev->irq = irq + 2;
- ssb_dprintk(KERN_INFO PFX
- "set_irq: core 0x%04x, irq %d => %d\n",
- dev->id.coreid, oldirq, irq);
/* clear the old irq */
if (oldirq == 0)
ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
- else
+ else if (oldirq != 5)
clear_irq(bus, oldirq);
/* assign the new one */
if (irq == 0) {
ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
} else {
+ u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
+ if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
+ u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
+ struct ssb_device *olddev = find_device(dev, oldipsflag);
+ if (olddev)
+ set_irq(olddev, 0);
+ }
irqflag <<= ipsflag_irq_shift[irq];
- irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
+ irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
ssb_write32(mdev, SSB_IPSFLAG, irqflag);
}
+ ssb_dprintk(KERN_INFO PFX
+ "set_irq: core 0x%04x, irq %d => %d\n",
+ dev->id.coreid, oldirq+2, irq+2);
+}
+
+static void print_irq(struct ssb_device *dev, unsigned int irq)
+{
+ int i;
+ static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
+ ssb_dprintk(KERN_INFO PFX
+ "core 0x%04x, irq :", dev->id.coreid);
+ for (i = 0; i <= 6; i++) {
+ ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
+ }
+ ssb_dprintk("\n");
+}
+
+static void dump_irq(struct ssb_bus *bus)
+{
+ int i;
+ for (i = 0; i < bus->nr_devices; i++) {
+ struct ssb_device *dev;
+ dev = &(bus->devices[i]);
+ print_irq(dev, ssb_mips_irq(dev));
+ }
}
static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
@@ -197,16 +253,23 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
/* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
for (irq = 2, i = 0; i < bus->nr_devices; i++) {
+ int mips_irq;
dev = &(bus->devices[i]);
- dev->irq = ssb_mips_irq(dev) + 2;
+ mips_irq = ssb_mips_irq(dev);
+ if (mips_irq > 4)
+ dev->irq = 0;
+ else
+ dev->irq = mips_irq + 2;
+ if (dev->irq > 5)
+ continue;
switch (dev->id.coreid) {
case SSB_DEV_USB11_HOST:
/* shouldn't need a separate irq line for non-4710, most of them have a proper
* external usb controller on the pci */
if ((bus->chip_id == 0x4710) && (irq <= 4)) {
set_irq(dev, irq++);
- break;
}
+ break;
/* fallthrough */
case SSB_DEV_PCI:
case SSB_DEV_ETHERNET:
@@ -220,6 +283,8 @@ void ssb_mipscore_init(struct ssb_mipscore *mcore)
}
}
}
+ ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
+ dump_irq(bus);
ssb_mips_serial_init(mcore);
ssb_mips_flash_detect(mcore);
diff --git a/drivers/staging/agnx/xmit.c b/drivers/staging/agnx/xmit.c
index 0e034081f3a..42db41070cf 100644
--- a/drivers/staging/agnx/xmit.c
+++ b/drivers/staging/agnx/xmit.c
@@ -384,7 +384,8 @@ void handle_rx_irq(struct agnx_priv *priv)
/* dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G"); */
} else
agnx_bug("Unknown packets type");
- ieee80211_rx_irqsafe(priv->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx_irqsafe(priv->hw, skb);
rx_desc_reinit(priv, i);
} while (priv->rx.idx++);
diff --git a/drivers/staging/at76_usb/at76_usb.c b/drivers/staging/at76_usb/at76_usb.c
index 3f303ae97b4..7b8aa5edf42 100644
--- a/drivers/staging/at76_usb/at76_usb.c
+++ b/drivers/staging/at76_usb/at76_usb.c
@@ -3134,7 +3134,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
netdev->name, __func__);
/* skip this packet */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (priv->tx_urb->status == -EINPROGRESS) {
@@ -3142,14 +3142,14 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
netdev->name, __func__);
/* skip this packet */
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
if (skb->len < ETH_HLEN) {
printk(KERN_ERR "%s: %s: skb too short (%d)\n",
netdev->name, __func__, skb->len);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
at76_ledtrig_tx_activity(); /* tell ledtrigger we send a packet */
@@ -3173,7 +3173,7 @@ static int at76_tx(struct sk_buff *skb, struct net_device *netdev)
skb->data[ETH_HLEN + 1],
skb->data[ETH_HLEN + 2]);
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
} else {
/* add RFC 1042 header in front */
diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c
index fad25b75304..84724187ec3 100644
--- a/drivers/staging/dst/dcore.c
+++ b/drivers/staging/dst/dcore.c
@@ -846,10 +846,9 @@ static dst_command_func dst_commands[] = {
/*
* Configuration parser.
*/
-static void cn_dst_callback(void *data)
+static void cn_dst_callback(struct cn_msg *msg)
{
struct dst_ctl *ctl;
- struct cn_msg *msg = data;
int err;
struct dst_ctl_ack ack;
struct dst_node *n = NULL, *tmp;
diff --git a/drivers/staging/epl/VirtualEthernetLinux.c b/drivers/staging/epl/VirtualEthernetLinux.c
index 077724a556c..7b7cce1b36e 100644
--- a/drivers/staging/epl/VirtualEthernetLinux.c
+++ b/drivers/staging/epl/VirtualEthernetLinux.c
@@ -223,7 +223,7 @@ static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p)
}
Exit:
- return 0;
+ return NETDEV_TX_OK;
}
diff --git a/drivers/staging/otus/usbdrv.c b/drivers/staging/otus/usbdrv.c
index 540cbbb826f..7cd87caa681 100644
--- a/drivers/staging/otus/usbdrv.c
+++ b/drivers/staging/otus/usbdrv.c
@@ -659,7 +659,7 @@ int usbdrv_xmit_frame(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
@@ -796,13 +796,13 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev)
if (vapId >= ZM_VAP_PORT_NUMBER)
{
dev_kfree_skb_irq(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#if 1
if (vap[vapId].openFlag == 0)
{
dev_kfree_skb_irq(skb);
- return 0;
+ return NETDEV_TX_OK;
}
#endif
@@ -819,7 +819,7 @@ int zfLnxVapXmitFrame(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
- return 0;
+ return NETDEV_TX_OK;
}
static const struct net_device_ops vap_netdev_ops = {
diff --git a/drivers/staging/otus/wrap_pkt.c b/drivers/staging/otus/wrap_pkt.c
index 5db0004c873..89a6b92f597 100644
--- a/drivers/staging/otus/wrap_pkt.c
+++ b/drivers/staging/otus/wrap_pkt.c
@@ -156,10 +156,7 @@ void zfLnxRecvEth(zdev_t* dev, zbuf_t* buf, u16_t port)
switch(netif_rx(buf))
#endif
{
- case NET_RX_BAD:
case NET_RX_DROP:
- case NET_RX_CN_MOD:
- case NET_RX_CN_HIGH:
break;
default:
macp->drv_stats.net_stats.rx_packets++;
diff --git a/drivers/staging/rt2860/rt_main_dev.c b/drivers/staging/rt2860/rt_main_dev.c
index f298b9bcec3..35c59d5aa99 100644
--- a/drivers/staging/rt2860/rt_main_dev.c
+++ b/drivers/staging/rt2860/rt_main_dev.c
@@ -862,7 +862,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb)
{
struct net_device *net_dev = skb->dev;
PRTMP_ADAPTER pAd = net_dev->ml_priv;
- int status = 0;
+ int status = NETDEV_TX_OK;
PNDIS_PACKET pPacket = (PNDIS_PACKET) skb;
{
@@ -892,7 +892,7 @@ int rt28xx_packet_xmit(struct sk_buff *skb)
STASendPackets((NDIS_HANDLE)pAd, (PPNDIS_PACKET) &pPacket, 1);
- status = 0;
+ status = NETDEV_TX_OK;
done:
return status;
@@ -923,7 +923,7 @@ INT rt28xx_send_packets(
if (!(net_dev->flags & IFF_UP))
{
RELEASE_NDIS_PACKET(pAd, (PNDIS_PACKET)skb_p, NDIS_STATUS_FAILURE);
- return 0;
+ return NETDEV_TX_OK;
}
NdisZeroMemory((PUCHAR)&skb_p->cb[CB_OFF], 15);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index 1294e05fcf1..1b774601b4a 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -802,13 +802,13 @@ int ieee80211_xmit(struct sk_buff *skb,
if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
stats->tx_packets++;
stats->tx_bytes += txb->payload_size;
- return 0;
+ return NETDEV_TX_OK;
}
ieee80211_txb_free(txb);
}
}
- return 0;
+ return NETDEV_TX_OK;
failed:
spin_unlock_irqrestore(&ieee->lock, flags);
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 7e2fecae813..26a59118d34 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -3040,7 +3040,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
spin_unlock_irqrestore(&priv->tx_lock,flags);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
rtl8180_tx(dev, skb->data, skb->len, priority,
@@ -3051,7 +3051,7 @@ int rtl8180_hard_start_xmit(struct sk_buff *skb,struct net_device *dev)
spin_unlock_irqrestore(&priv->tx_lock,flags);
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
// longpre 144+48 shortpre 72+24
diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c
index ed47db5ce5f..b01a2822a8e 100644
--- a/drivers/staging/slicoss/slicoss.c
+++ b/drivers/staging/slicoss/slicoss.c
@@ -845,7 +845,7 @@ static int slic_xmit_start(struct sk_buff *skb, struct net_device *dev)
hcmd->paddrh, DONT_FLUSH);
}
xmit_done:
- return 0;
+ return NETDEV_TX_OK;
xmit_fail:
slic_xmit_fail(adapter, skb, offloadcmd, skbtype, status);
goto xmit_done;
diff --git a/drivers/staging/stlc45xx/stlc45xx.c b/drivers/staging/stlc45xx/stlc45xx.c
index cfdaac9b747..52744faedbf 100644
--- a/drivers/staging/stlc45xx/stlc45xx.c
+++ b/drivers/staging/stlc45xx/stlc45xx.c
@@ -1429,7 +1429,8 @@ static int stlc45xx_rx_data(struct stlc45xx *stlc, struct sk_buff *skb)
stlc45xx_debug(DEBUG_RX, "rx data 0x%p %d B", skb->data, skb->len);
stlc45xx_dump(DEBUG_RX_CONTENT, skb->data, skb->len);
- ieee80211_rx(stlc->hw, skb, &status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+ ieee80211_rx(stlc->hw, skb);
return 0;
}
diff --git a/drivers/staging/winbond/wb35rx.c b/drivers/staging/winbond/wb35rx.c
index 3e8cf08b87e..b905e7b43a1 100644
--- a/drivers/staging/winbond/wb35rx.c
+++ b/drivers/staging/winbond/wb35rx.c
@@ -40,7 +40,8 @@ static void packet_came(struct ieee80211_hw *hw, char *pRxBufferAddress, int Pac
rx_status.phymode = MODE_IEEE80211B;
*/
- ieee80211_rx_irqsafe(hw, skb, &rx_status);
+ memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ ieee80211_rx_irqsafe(hw, skb);
}
static void Wb35Rx_adjust(PDESCRIPTOR pRxDes)
diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c
index 90f499e00dc..c273c034a83 100644
--- a/drivers/staging/wlan-ng/p80211netdev.c
+++ b/drivers/staging/wlan-ng/p80211netdev.c
@@ -354,7 +354,7 @@ static int p80211knetdev_hard_start_xmit(struct sk_buff *skb,
p80211_metawep_t p80211_wep;
if (skb == NULL)
- return 0;
+ return NETDEV_TX_OK;
if (wlandev->state != WLAN_DEVICE_OPEN) {
result = 1;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 38bfdb0f666..3f104599347 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -550,7 +550,7 @@ static void acm_waker(struct work_struct *waker)
static int acm_tty_open(struct tty_struct *tty, struct file *filp)
{
struct acm *acm;
- int rv = -EINVAL;
+ int rv = -ENODEV;
int i;
dbg("Entering acm_tty_open.");
@@ -677,7 +677,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
/* Perform the closing process and see if we need to do the hardware
shutdown */
- if (tty_port_close_start(&acm->port, tty, filp) == 0)
+ if (!acm || tty_port_close_start(&acm->port, tty, filp) == 0)
return;
acm_port_down(acm, 0);
tty_port_close_end(&acm->port, tty);
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 96fb118355b..d17f1082df9 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -256,7 +256,7 @@ out:
dev_kfree_skb(skb);
dev->stats.tx_dropped++;
}
- return 0;
+ return NETDEV_TX_OK;
}
static int pn_net_mtu(struct net_device *dev, int new_mtu)
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 016f63b3902..aac69b591ae 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -487,7 +487,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net)
if (!in) {
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
/* apply outgoing CDC or RNDIS filters */
@@ -506,7 +506,7 @@ static int eth_start_xmit(struct sk_buff *skb, struct net_device *net)
type = USB_CDC_PACKET_TYPE_ALL_MULTICAST;
if (!(cdc_filter & type)) {
dev_kfree_skb_any(skb);
- return 0;
+ return NETDEV_TX_OK;
}
}
/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
@@ -586,7 +586,7 @@ drop:
list_add(&req->list, &dev->tx_reqs);
spin_unlock_irqrestore(&dev->req_lock, flags);
}
- return 0;
+ return NETDEV_TX_OK;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index d595aa5586a..a84216464ca 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -333,6 +333,9 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
{
struct usb_serial_port *port = tty->driver_data;
+ if (!port)
+ return;
+
dbg("%s - port %d", __func__, port->number);
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d6d65ef85f5..8afcf08eba9 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -616,6 +616,8 @@ config FB_STI
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select STI_CONSOLE
+ select VT
default y
---help---
STI refers to the HP "Standard Text Interface" which is a set of
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 018850c116c..497ff8af03e 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2414,7 +2414,10 @@ static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
if (err)
return err;
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- return fbhw->encode_fix(fix, &par);
+ mutex_lock(&info->mm_lock);
+ err = fbhw->encode_fix(fix, &par);
+ mutex_unlock(&info->mm_lock);
+ return err;
}
static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -2743,7 +2746,9 @@ static int atafb_set_par(struct fb_info *info)
/* Decode wanted screen parameters */
fbhw->decode_var(&info->var, par);
+ mutex_lock(&info->mm_lock);
fbhw->encode_fix(&info->fix, par);
+ mutex_unlock(&info->mm_lock);
/* Set new videomode */
ata_set_par(par);
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 5afd64482f5..cb88394ba99 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -270,7 +270,9 @@ static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
smem_len = (var->xres_virtual * var->yres_virtual
* ((var->bits_per_pixel + 7) / 8));
+ mutex_lock(&info->mm_lock);
info->fix.smem_len = max(smem_len, sinfo->smem_len);
+ mutex_unlock(&info->mm_lock);
info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
(dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index 7691e73823d..1f39a62f899 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -187,6 +187,8 @@ struct atyfb_par {
int mtrr_reg;
#endif
u32 mem_cntl;
+ struct crtc saved_crtc;
+ union aty_pll saved_pll;
};
/*
@@ -217,6 +219,7 @@ struct atyfb_par {
#define M64F_XL_DLL 0x00080000
#define M64F_MFB_FORCE_4 0x00100000
#define M64F_HW_TRIPLE 0x00200000
+#define M64F_XL_MEM 0x00400000
/*
* Register access
*/
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 1207c208a30..63d3739d43a 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -66,6 +66,8 @@
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/backlight.h>
+#include <linux/reboot.h>
+#include <linux/dmi.h>
#include <asm/io.h>
#include <linux/uaccess.h>
@@ -249,8 +251,6 @@ static int aty_init(struct fb_info *info);
static int store_video_par(char *videopar, unsigned char m64_num);
#endif
-static struct crtc saved_crtc;
-static union aty_pll saved_pll;
static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
@@ -261,6 +261,8 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);
static int read_aty_sense(const struct atyfb_par *par);
#endif
+static DEFINE_MUTEX(reboot_lock);
+static struct fb_info *reboot_info;
/*
* Interface used by the world
@@ -361,8 +363,8 @@ static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, };
#define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
#define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
-#define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4)
-#define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS)
+#define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM)
+#define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM | M64F_MOBIL_BUS)
static struct {
u16 pci_id;
@@ -539,6 +541,7 @@ static char ram_edo[] __devinitdata = "EDO";
static char ram_sdram[] __devinitdata = "SDRAM (1:1)";
static char ram_sgram[] __devinitdata = "SGRAM (1:1)";
static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)";
+static char ram_wram[] __devinitdata = "WRAM";
static char ram_off[] __devinitdata = "OFF";
#endif /* CONFIG_FB_ATY_CT */
@@ -553,6 +556,10 @@ static char *aty_gx_ram[8] __devinitdata = {
#ifdef CONFIG_FB_ATY_CT
static char *aty_ct_ram[8] __devinitdata = {
ram_off, ram_dram, ram_edo, ram_edo,
+ ram_sdram, ram_sgram, ram_wram, ram_resv
+};
+static char *aty_xl_ram[8] __devinitdata = {
+ ram_off, ram_dram, ram_edo, ram_edo,
ram_sdram, ram_sgram, ram_sdram32, ram_resv
};
#endif /* CONFIG_FB_ATY_CT */
@@ -760,6 +767,17 @@ static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
#endif /* CONFIG_FB_ATY_GENERIC_LCD */
}
+static u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp)
+{
+ u32 line_length = vxres * bpp / 8;
+
+ if (par->ram_type == SGRAM ||
+ (!M64_HAS(XL_MEM) && par->ram_type == WRAM))
+ line_length = (line_length + 63) & ~63;
+
+ return line_length;
+}
+
static int aty_var_to_crtc(const struct fb_info *info,
const struct fb_var_screeninfo *var, struct crtc *crtc)
{
@@ -769,13 +787,14 @@ static int aty_var_to_crtc(const struct fb_info *info,
u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;
u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;
u32 pix_width, dp_pix_width, dp_chain_mask;
+ u32 line_length;
/* input */
- xres = var->xres;
+ xres = (var->xres + 7) & ~7;
yres = var->yres;
- vxres = var->xres_virtual;
+ vxres = (var->xres_virtual + 7) & ~7;
vyres = var->yres_virtual;
- xoffset = var->xoffset;
+ xoffset = (var->xoffset + 7) & ~7;
yoffset = var->yoffset;
bpp = var->bits_per_pixel;
if (bpp == 16)
@@ -827,7 +846,9 @@ static int aty_var_to_crtc(const struct fb_info *info,
} else
FAIL("invalid bpp");
- if (vxres * vyres * bpp / 8 > info->fix.smem_len)
+ line_length = calc_line_length(par, vxres, bpp);
+
+ if (vyres * line_length > info->fix.smem_len)
FAIL("not enough video RAM");
h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
@@ -969,7 +990,9 @@ static int aty_var_to_crtc(const struct fb_info *info,
crtc->xoffset = xoffset;
crtc->yoffset = yoffset;
crtc->bpp = bpp;
- crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+ crtc->off_pitch =
+ ((yoffset * line_length + xoffset * bpp / 8) / 8) |
+ ((line_length / bpp) << 22);
crtc->vline_crnt_vline = 0;
crtc->h_tot_disp = h_total | (h_disp<<16);
@@ -1394,7 +1417,9 @@ static int atyfb_set_par(struct fb_info *info)
}
aty_st_8(DAC_MASK, 0xff, par);
- info->fix.line_length = var->xres_virtual * var->bits_per_pixel/8;
+ info->fix.line_length = calc_line_length(par, var->xres_virtual,
+ var->bits_per_pixel);
+
info->fix.visual = var->bits_per_pixel <= 8 ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
@@ -1505,10 +1530,12 @@ static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info)
{
u32 xoffset = info->var.xoffset;
u32 yoffset = info->var.yoffset;
- u32 vxres = par->crtc.vxres;
+ u32 line_length = info->fix.line_length;
u32 bpp = info->var.bits_per_pixel;
- par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
+ par->crtc.off_pitch =
+ ((yoffset * line_length + xoffset * bpp / 8) / 8) |
+ ((line_length / bpp) << 22);
}
@@ -2201,7 +2228,7 @@ static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
const int *refresh_tbl;
int i, size;
- if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) {
+ if (M64_HAS(XL_MEM)) {
refresh_tbl = ragexl_tbl;
size = ARRAY_SIZE(ragexl_tbl);
} else {
@@ -2335,7 +2362,10 @@ static int __devinit aty_init(struct fb_info *info)
par->pll_ops = &aty_pll_ct;
par->bus_type = PCI;
par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07);
- ramname = aty_ct_ram[par->ram_type];
+ if (M64_HAS(XL_MEM))
+ ramname = aty_xl_ram[par->ram_type];
+ else
+ ramname = aty_ct_ram[par->ram_type];
/* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
par->pll_limits.mclk = 63;
@@ -2390,9 +2420,9 @@ static int __devinit aty_init(struct fb_info *info)
#endif /* CONFIG_FB_ATY_CT */
/* save previous video mode */
- aty_get_crtc(par, &saved_crtc);
+ aty_get_crtc(par, &par->saved_crtc);
if(par->pll_ops->get_pll)
- par->pll_ops->get_pll(info, &saved_pll);
+ par->pll_ops->get_pll(info, &par->saved_pll);
par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
gtb_memsize = M64_HAS(GTB_DSP);
@@ -2667,8 +2697,8 @@ static int __devinit aty_init(struct fb_info *info)
aty_init_exit:
/* restore video mode */
- aty_set_crtc(par, &saved_crtc);
- par->pll_ops->set_pll(info, &saved_pll);
+ aty_set_crtc(par, &par->saved_crtc);
+ par->pll_ops->set_pll(info, &par->saved_pll);
#ifdef CONFIG_MTRR
if (par->mtrr_reg >= 0) {
@@ -3502,6 +3532,11 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
par->mmap_map[1].prot_flag = _PAGE_E;
#endif /* __sparc__ */
+ mutex_lock(&reboot_lock);
+ if (!reboot_info)
+ reboot_info = info;
+ mutex_unlock(&reboot_lock);
+
return 0;
err_release_io:
@@ -3614,8 +3649,8 @@ static void __devexit atyfb_remove(struct fb_info *info)
struct atyfb_par *par = (struct atyfb_par *) info->par;
/* restore video mode */
- aty_set_crtc(par, &saved_crtc);
- par->pll_ops->set_pll(info, &saved_pll);
+ aty_set_crtc(par, &par->saved_crtc);
+ par->pll_ops->set_pll(info, &par->saved_pll);
unregister_framebuffer(info);
@@ -3661,6 +3696,11 @@ static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
+ mutex_lock(&reboot_lock);
+ if (reboot_info == info)
+ reboot_info = NULL;
+ mutex_unlock(&reboot_lock);
+
atyfb_remove(info);
}
@@ -3808,6 +3848,56 @@ static int __init atyfb_setup(char *options)
}
#endif /* MODULE */
+static int atyfb_reboot_notify(struct notifier_block *nb,
+ unsigned long code, void *unused)
+{
+ struct atyfb_par *par;
+
+ if (code != SYS_RESTART)
+ return NOTIFY_DONE;
+
+ mutex_lock(&reboot_lock);
+
+ if (!reboot_info)
+ goto out;
+
+ if (!lock_fb_info(reboot_info))
+ goto out;
+
+ par = reboot_info->par;
+
+ /*
+ * HP OmniBook 500's BIOS doesn't like the state of the
+ * hardware after atyfb has been used. Restore the hardware
+ * to the original state to allow successful reboots.
+ */
+ aty_set_crtc(par, &par->saved_crtc);
+ par->pll_ops->set_pll(reboot_info, &par->saved_pll);
+
+ unlock_fb_info(reboot_info);
+ out:
+ mutex_unlock(&reboot_lock);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block atyfb_reboot_notifier = {
+ .notifier_call = atyfb_reboot_notify,
+};
+
+static const struct dmi_system_id atyfb_reboot_ids[] = {
+ {
+ .ident = "HP OmniBook 500",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"),
+ },
+ },
+
+ { }
+};
+
static int __init atyfb_init(void)
{
int err1 = 1, err2 = 1;
@@ -3826,11 +3916,20 @@ static int __init atyfb_init(void)
err2 = atyfb_atari_probe();
#endif
- return (err1 && err2) ? -ENODEV : 0;
+ if (err1 && err2)
+ return -ENODEV;
+
+ if (dmi_check_system(atyfb_reboot_ids))
+ register_reboot_notifier(&atyfb_reboot_notifier);
+
+ return 0;
}
static void __exit atyfb_exit(void)
{
+ if (dmi_check_system(atyfb_reboot_ids))
+ unregister_reboot_notifier(&atyfb_reboot_notifier);
+
#ifdef CONFIG_PCI
pci_unregister_driver(&atyfb_driver);
#endif
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
index 0cc9724e61a..51fcc0a2c94 100644
--- a/drivers/video/aty/mach64_accel.c
+++ b/drivers/video/aty/mach64_accel.c
@@ -63,14 +63,17 @@ static void reset_GTC_3D_engine(const struct atyfb_par *par)
void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
{
u32 pitch_value;
+ u32 vxres;
/* determine modal information from global mode structure */
- pitch_value = info->var.xres_virtual;
+ pitch_value = info->fix.line_length / (info->var.bits_per_pixel / 8);
+ vxres = info->var.xres_virtual;
if (info->var.bits_per_pixel == 24) {
/* In 24 bpp, the engine is in 8 bpp - this requires that all */
/* horizontal coordinates and widths must be adjusted */
pitch_value *= 3;
+ vxres *= 3;
}
/* On GTC (RagePro), we need to reset the 3D engine before */
@@ -133,7 +136,7 @@ void aty_init_engine(struct atyfb_par *par, struct fb_info *info)
aty_st_le32(SC_LEFT, 0, par);
aty_st_le32(SC_TOP, 0, par);
aty_st_le32(SC_BOTTOM, par->crtc.vyres - 1, par);
- aty_st_le32(SC_RIGHT, pitch_value - 1, par);
+ aty_st_le32(SC_RIGHT, vxres - 1, par);
/* set background color to minimum value (usually BLACK) */
aty_st_le32(DP_BKGD_CLR, 0, par);
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c
index 1dae7f8f3c6..51422fc4f60 100644
--- a/drivers/video/backlight/tdo24m.c
+++ b/drivers/video/backlight/tdo24m.c
@@ -356,7 +356,7 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
lcd->power = FB_BLANK_POWERDOWN;
lcd->mode = MODE_VGA; /* default to VGA */
- lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, sizeof(GFP_KERNEL));
+ lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, GFP_KERNEL);
if (lcd->buf == NULL) {
kfree(lcd);
return -ENOMEM;
diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c
index 7bad24ed04e..108b89e09a8 100644
--- a/drivers/video/cobalt_lcdfb.c
+++ b/drivers/video/cobalt_lcdfb.c
@@ -1,7 +1,7 @@
/*
* Cobalt server LCD frame buffer driver.
*
- * Copyright (C) 2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2008 Yoichi Yuasa <yuasa@linux-mips.org>
*
* 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
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index f8a09bf8d0c..53ea05645ff 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1310,8 +1310,6 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
-__acquires(&info->lock)
-__releases(&info->lock)
{
int fbidx = iminor(file->f_path.dentry->d_inode);
struct fb_info *info = registered_fb[fbidx];
@@ -1325,16 +1323,14 @@ __releases(&info->lock)
off = vma->vm_pgoff << PAGE_SHIFT;
if (!fb)
return -ENODEV;
+ mutex_lock(&info->mm_lock);
if (fb->fb_mmap) {
int res;
- mutex_lock(&info->lock);
res = fb->fb_mmap(info, vma);
- mutex_unlock(&info->lock);
+ mutex_unlock(&info->mm_lock);
return res;
}
- mutex_lock(&info->lock);
-
/* frame buffer memory */
start = info->fix.smem_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
@@ -1342,13 +1338,13 @@ __releases(&info->lock)
/* memory mapped io */
off -= len;
if (info->var.accel_flags) {
- mutex_unlock(&info->lock);
+ mutex_unlock(&info->mm_lock);
return -EINVAL;
}
start = info->fix.mmio_start;
len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
}
- mutex_unlock(&info->lock);
+ mutex_unlock(&info->mm_lock);
start &= PAGE_MASK;
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;
@@ -1518,6 +1514,7 @@ register_framebuffer(struct fb_info *fb_info)
break;
fb_info->node = i;
mutex_init(&fb_info->lock);
+ mutex_init(&fb_info->mm_lock);
fb_info->dev = device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index f153c581cbd..0bf2190928d 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -750,24 +750,26 @@ static void update_lcdc(struct fb_info *info)
static int map_video_memory(struct fb_info *info)
{
phys_addr_t phys;
+ u32 smem_len = info->fix.line_length * info->var.yres_virtual;
pr_debug("info->var.xres_virtual = %d\n", info->var.xres_virtual);
pr_debug("info->var.yres_virtual = %d\n", info->var.yres_virtual);
pr_debug("info->fix.line_length = %d\n", info->fix.line_length);
+ pr_debug("MAP_VIDEO_MEMORY: smem_len = %u\n", smem_len);
- info->fix.smem_len = info->fix.line_length * info->var.yres_virtual;
- pr_debug("MAP_VIDEO_MEMORY: smem_len = %d\n", info->fix.smem_len);
- info->screen_base = fsl_diu_alloc(info->fix.smem_len, &phys);
+ info->screen_base = fsl_diu_alloc(smem_len, &phys);
if (info->screen_base == NULL) {
printk(KERN_ERR "Unable to allocate fb memory\n");
return -ENOMEM;
}
+ mutex_lock(&info->mm_lock);
info->fix.smem_start = (unsigned long) phys;
+ info->fix.smem_len = smem_len;
+ mutex_unlock(&info->mm_lock);
info->screen_size = info->fix.smem_len;
pr_debug("Allocated fb @ paddr=0x%08lx, size=%d.\n",
- info->fix.smem_start,
- info->fix.smem_len);
+ info->fix.smem_start, info->fix.smem_len);
pr_debug("screen base %p\n", info->screen_base);
return 0;
@@ -776,9 +778,11 @@ static int map_video_memory(struct fb_info *info)
static void unmap_video_memory(struct fb_info *info)
{
fsl_diu_free(info->screen_base, info->fix.smem_len);
+ mutex_lock(&info->mm_lock);
info->screen_base = NULL;
info->fix.smem_start = 0;
info->fix.smem_len = 0;
+ mutex_unlock(&info->mm_lock);
}
/*
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 2e940199fc8..71960672d72 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1090,8 +1090,10 @@ static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, "I810");
+ mutex_lock(&info->mm_lock);
fix->smem_start = par->fb.physical;
fix->smem_len = par->fb.size;
+ mutex_unlock(&info->mm_lock);
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
fix->xpanstep = 8;
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 8e7a275df50..59c3a2e1491 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -724,8 +724,10 @@ static void matroxfb_update_fix(WPMINFO2)
struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix;
DBG(__func__)
+ mutex_lock(&ACCESS_FBINFO(fbcon).mm_lock);
fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes);
+ mutex_unlock(&ACCESS_FBINFO(fbcon).mm_lock);
}
static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -2081,6 +2083,7 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
spin_lock_init(&ACCESS_FBINFO(lock.accel));
init_rwsem(&ACCESS_FBINFO(crtc2.lock));
init_rwsem(&ACCESS_FBINFO(altout.lock));
+ mutex_init(&ACCESS_FBINFO(fbcon).mm_lock);
ACCESS_FBINFO(irq_flags) = 0;
init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait));
init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait));
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
index 7ac4c5f6145..909e10a1189 100644
--- a/drivers/video/matrox/matroxfb_crtc2.c
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -289,13 +289,16 @@ static int matroxfb_dh_release(struct fb_info* info, int user) {
#undef m2info
}
-static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) {
+static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info)
+{
struct fb_fix_screeninfo *fix = &m2info->fbcon.fix;
strcpy(fix->id, "MATROX DH");
+ mutex_lock(&m2info->fbcon.mm_lock);
fix->smem_start = m2info->video.base;
fix->smem_len = m2info->video.len_usable;
+ mutex_unlock(&m2info->fbcon.mm_lock);
fix->ypanstep = 1;
fix->ywrapstep = 0;
fix->xpanstep = 8; /* TBD */
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index b7af5256e88..567fb944bd2 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -669,7 +669,7 @@ static uint32_t bpp_to_pixfmt(int bpp)
}
static int mx3fb_blank(int blank, struct fb_info *fbi);
-static int mx3fb_map_video_memory(struct fb_info *fbi);
+static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len);
static int mx3fb_unmap_video_memory(struct fb_info *fbi);
/**
@@ -742,8 +742,7 @@ static int mx3fb_set_par(struct fb_info *fbi)
if (fbi->fix.smem_start)
mx3fb_unmap_video_memory(fbi);
- fbi->fix.smem_len = mem_len;
- if (mx3fb_map_video_memory(fbi) < 0) {
+ if (mx3fb_map_video_memory(fbi, mem_len) < 0) {
mutex_unlock(&mx3_fbi->mutex);
return -ENOMEM;
}
@@ -1198,6 +1197,7 @@ static int mx3fb_resume(struct platform_device *pdev)
/**
* mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer.
* @fbi: framebuffer information pointer
+ * @mem_len: length of mapped memory
* @return: Error code indicating success or failure
*
* This buffer is remapped into a non-cached, non-buffered, memory region to
@@ -1205,23 +1205,26 @@ static int mx3fb_resume(struct platform_device *pdev)
* area is remapped, all virtual memory access to the video memory should occur
* at the new region.
*/
-static int mx3fb_map_video_memory(struct fb_info *fbi)
+static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len)
{
int retval = 0;
dma_addr_t addr;
fbi->screen_base = dma_alloc_writecombine(fbi->device,
- fbi->fix.smem_len,
+ mem_len,
&addr, GFP_DMA);
if (!fbi->screen_base) {
dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n",
- fbi->fix.smem_len);
+ mem_len);
retval = -EBUSY;
goto err0;
}
+ mutex_lock(&fbi->mm_lock);
fbi->fix.smem_start = addr;
+ fbi->fix.smem_len = mem_len;
+ mutex_unlock(&fbi->mm_lock);
dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n",
(uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len);
@@ -1251,8 +1254,10 @@ static int mx3fb_unmap_video_memory(struct fb_info *fbi)
fbi->screen_base, fbi->fix.smem_start);
fbi->screen_base = 0;
+ mutex_lock(&fbi->mm_lock);
fbi->fix.smem_start = 0;
fbi->fix.smem_len = 0;
+ mutex_unlock(&fbi->mm_lock);
return 0;
}
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 060d72fe57c..4ea99bfc37b 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -393,8 +393,10 @@ static void set_fb_fix(struct fb_info *fbi)
rg = &plane->fbdev->mem_desc.region[plane->idx];
fbi->screen_base = rg->vaddr;
+ mutex_lock(&fbi->mm_lock);
fix->smem_start = rg->paddr;
fix->smem_len = rg->size;
+ mutex_unlock(&fbi->mm_lock);
fix->type = FB_TYPE_PACKED_PIXELS;
bpp = var->bits_per_pixel;
@@ -886,8 +888,10 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
* plane memory is dealloce'd, the other
* screen parameters in var / fix are invalid.
*/
+ mutex_lock(&fbi->mm_lock);
fbi->fix.smem_start = 0;
fbi->fix.smem_len = 0;
+ mutex_unlock(&fbi->mm_lock);
}
}
}
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 03b3670130a..bacfabd9ce1 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -141,7 +141,9 @@ static int platinumfb_set_par (struct fb_info *info)
offset = 0x10;
info->screen_base = pinfo->frame_buffer + init->fb_offset + offset;
+ mutex_lock(&info->mm_lock);
info->fix.smem_start = (pinfo->frame_buffer_phys) + init->fb_offset + offset;
+ mutex_unlock(&info->mm_lock);
info->fix.visual = (pinfo->cmode == CMODE_8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
info->fix.line_length = vmode_attrs[pinfo->vmode-1].hres * (1<<pinfo->cmode)
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 0889d50c328..6506117c134 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -815,8 +815,10 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb)
ofb->video_mem_phys = virt_to_phys(ofb->video_mem);
ofb->video_mem_size = size;
+ mutex_lock(&ofb->fb.mm_lock);
ofb->fb.fix.smem_start = ofb->video_mem_phys;
ofb->fb.fix.smem_len = ofb->fb.fix.line_length * var->yres_virtual;
+ mutex_unlock(&ofb->fb.mm_lock);
ofb->fb.screen_base = ofb->video_mem;
return 0;
}
diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c
index 653bdfee305..9f6d6e61f0c 100644
--- a/drivers/video/sh7760fb.c
+++ b/drivers/video/sh7760fb.c
@@ -120,18 +120,6 @@ static int sh7760_setcolreg (u_int regno,
return 0;
}
-static void encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info,
- unsigned long stride)
-{
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, "sh7760-lcdc");
-
- fix->smem_start = (unsigned long)info->screen_base;
- fix->smem_len = info->screen_size;
-
- fix->line_length = stride;
-}
-
static int sh7760fb_get_color_info(struct device *dev,
u16 lddfr, int *bpp, int *gray)
{
@@ -334,7 +322,8 @@ static int sh7760fb_set_par(struct fb_info *info)
iowrite32(ldsarl, par->base + LDSARL); /* mem for lower half of DSTN */
- encode_fix(&info->fix, info, stride);
+ info->fix.line_length = stride;
+
sh7760fb_check_var(&info->var, info);
sh7760fb_blank(FB_BLANK_UNBLANK, info); /* panel on! */
@@ -435,6 +424,8 @@ static int sh7760fb_alloc_mem(struct fb_info *info)
info->screen_base = fbmem;
info->screen_size = vram;
+ info->fix.smem_start = (unsigned long)info->screen_base;
+ info->fix.smem_len = info->screen_size;
return 0;
}
@@ -520,6 +511,8 @@ static int __devinit sh7760fb_probe(struct platform_device *pdev)
info->var.transp.length = 0;
info->var.transp.msb_right = 0;
+ strcpy(info->fix.id, "sh7760-lcdc");
+
/* set the DON2 bit now, before cmap allocation, as it will randomize
* palette memory.
*/
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index f10d2fbeda0..da983b720f0 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/atomic.h>
@@ -33,6 +34,7 @@ struct sh_mobile_lcdc_chan {
struct fb_info info;
dma_addr_t dma_handle;
struct fb_deferred_io defio;
+ struct scatterlist *sglist;
unsigned long frame_end;
wait_queue_head_t frame_end_wait;
};
@@ -206,16 +208,38 @@ static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) {}
static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv) {}
#endif
+static int sh_mobile_lcdc_sginit(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ struct sh_mobile_lcdc_chan *ch = info->par;
+ unsigned int nr_pages_max = info->fix.smem_len >> PAGE_SHIFT;
+ struct page *page;
+ int nr_pages = 0;
+
+ sg_init_table(ch->sglist, nr_pages_max);
+
+ list_for_each_entry(page, pagelist, lru)
+ sg_set_page(&ch->sglist[nr_pages++], page, PAGE_SIZE, 0);
+
+ return nr_pages;
+}
+
static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
struct list_head *pagelist)
{
struct sh_mobile_lcdc_chan *ch = info->par;
+ unsigned int nr_pages;
/* enable clocks before accessing hardware */
sh_mobile_lcdc_clk_on(ch->lcdc);
+ nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
+ dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
+
/* trigger panel update */
lcdc_write_chan(ch, LDSM2R, 1);
+
+ dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
}
static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
@@ -846,21 +870,31 @@ static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
}
for (i = 0; i < j; i++) {
- error = register_framebuffer(&priv->ch[i].info);
+ struct sh_mobile_lcdc_chan *ch = priv->ch + i;
+
+ info = &ch->info;
+
+ if (info->fbdefio) {
+ priv->ch->sglist = vmalloc(sizeof(struct scatterlist) *
+ info->fix.smem_len >> PAGE_SHIFT);
+ if (!priv->ch->sglist) {
+ dev_err(&pdev->dev, "cannot allocate sglist\n");
+ goto err1;
+ }
+ }
+
+ error = register_framebuffer(info);
if (error < 0)
goto err1;
- }
- for (i = 0; i < j; i++) {
- info = &priv->ch[i].info;
dev_info(info->dev,
"registered %s/%s as %dx%d %dbpp.\n",
pdev->name,
- (priv->ch[i].cfg.chan == LCDC_CHAN_MAINLCD) ?
+ (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
"mainlcd" : "sublcd",
- (int) priv->ch[i].cfg.lcd_cfg.xres,
- (int) priv->ch[i].cfg.lcd_cfg.yres,
- priv->ch[i].cfg.bpp);
+ (int) ch->cfg.lcd_cfg.xres,
+ (int) ch->cfg.lcd_cfg.yres,
+ ch->cfg.bpp);
/* deferred io mode: disable clock to save power */
if (info->fbdefio)
@@ -892,6 +926,9 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
if (!info->device)
continue;
+ if (priv->ch[i].sglist)
+ vfree(priv->ch[i].sglist);
+
dma_free_coherent(&pdev->dev, info->fix.smem_len,
info->screen_base, priv->ch[i].dma_handle);
fb_dealloc_cmap(&info->cmap);
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 7072d19080d..fd33455389b 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -1847,8 +1847,10 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
strcpy(fix->id, ivideo->myid);
+ mutex_lock(&info->mm_lock);
fix->smem_start = ivideo->video_base + ivideo->video_offset;
fix->smem_len = ivideo->sisfb_mem;
+ mutex_unlock(&info->mm_lock);
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index eb5d73a0670..16d4f4c7d52 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -145,7 +145,7 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
#define SM501_MEMF_ACCEL (8)
static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
- unsigned int why, size_t size)
+ unsigned int why, size_t size, u32 smem_len)
{
struct sm501fb_par *par;
struct fb_info *fbi;
@@ -172,7 +172,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
if (ptr > 0)
ptr &= ~(PAGE_SIZE - 1);
- if (fbi && ptr < fbi->fix.smem_len)
+ if (fbi && ptr < smem_len)
return -ENOMEM;
break;
@@ -197,7 +197,7 @@ static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem,
case SM501_MEMF_ACCEL:
fbi = inf->fb[HEAD_CRT];
- ptr = fbi ? fbi->fix.smem_len : 0;
+ ptr = fbi ? smem_len : 0;
fbi = inf->fb[HEAD_PANEL];
if (fbi) {
@@ -413,6 +413,7 @@ static int sm501fb_set_par_common(struct fb_info *info,
unsigned int mem_type;
unsigned int clock_type;
unsigned int head_addr;
+ unsigned int smem_len;
dev_dbg(fbi->dev, "%s: %dx%d, bpp = %d, virtual %dx%d\n",
__func__, var->xres, var->yres, var->bits_per_pixel,
@@ -453,18 +454,20 @@ static int sm501fb_set_par_common(struct fb_info *info,
/* allocate fb memory within 501 */
info->fix.line_length = (var->xres_virtual * var->bits_per_pixel)/8;
- info->fix.smem_len = info->fix.line_length * var->yres_virtual;
+ smem_len = info->fix.line_length * var->yres_virtual;
dev_dbg(fbi->dev, "%s: line length = %u\n", __func__,
info->fix.line_length);
- if (sm501_alloc_mem(fbi, &par->screen, mem_type,
- info->fix.smem_len)) {
+ if (sm501_alloc_mem(fbi, &par->screen, mem_type, smem_len, smem_len)) {
dev_err(fbi->dev, "no memory available\n");
return -ENOMEM;
}
+ mutex_lock(&info->mm_lock);
info->fix.smem_start = fbi->fbmem_res->start + par->screen.sm_addr;
+ info->fix.smem_len = smem_len;
+ mutex_unlock(&info->mm_lock);
info->screen_base = fbi->fbmem + par->screen.sm_addr;
info->screen_size = info->fix.smem_len;
@@ -637,7 +640,8 @@ static int sm501fb_set_par_crt(struct fb_info *info)
if ((control & SM501_DC_CRT_CONTROL_SEL) == 0) {
/* the head is displaying panel data... */
- sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0);
+ sm501_alloc_mem(fbi, &par->screen, SM501_MEMF_CRT, 0,
+ info->fix.smem_len);
goto out_update;
}
@@ -1289,7 +1293,8 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base)
par->cursor_regs = info->regs + reg_base;
- ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024);
+ ret = sm501_alloc_mem(info, &par->cursor, SM501_MEMF_CURSOR, 1024,
+ fbi->fix.smem_len);
if (ret < 0)
return ret;
@@ -1619,6 +1624,8 @@ static int __devinit sm501fb_start_one(struct sm501fb_info *info,
if (!fbi)
return 0;
+ mutex_init(&info->fb[head]->mm_lock);
+
ret = sm501fb_init_fb(info->fb[head], head, drvname);
if (ret) {
dev_err(info->dev, "cannot initialise fb %s\n", drvname);
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index ca5b4643a40..e98baf6916b 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -67,9 +67,8 @@ static DEFINE_MUTEX(uvfb_lock);
* find the kernel part of the task struct, copy the registers and
* the buffer contents and then complete the task.
*/
-static void uvesafb_cn_callback(void *data)
+static void uvesafb_cn_callback(struct cn_msg *msg)
{
- struct cn_msg *msg = data;
struct uvesafb_task *utask;
struct uvesafb_ktask *task;
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index d0674f1e3f1..8a141c2c637 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -523,6 +523,7 @@ static int w100fb_set_par(struct fb_info *info)
info->fix.ywrapstep = 0;
info->fix.line_length = par->xres * BITS_PER_PIXEL / 8;
+ mutex_lock(&info->mm_lock);
if ((par->xres*par->yres*BITS_PER_PIXEL/8) > (MEM_INT_SIZE+1)) {
par->extmem_active = 1;
info->fix.smem_len = par->mach->mem->size+1;
@@ -530,6 +531,7 @@ static int w100fb_set_par(struct fb_info *info)
par->extmem_active = 0;
info->fix.smem_len = MEM_INT_SIZE+1;
}
+ mutex_unlock(&info->mm_lock);
w100fb_activate_var(par);
}
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index fdf72851c57..52ccb3d3a96 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -306,9 +306,8 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm
return error;
}
-static void w1_cn_callback(void *data)
+static void w1_cn_callback(struct cn_msg *msg)
{
- struct cn_msg *msg = data;
struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1);
struct w1_netlink_cmd *cmd;
struct w1_slave *sl;
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
index a4fe7a38d9b..3bde56bce63 100644
--- a/drivers/watchdog/wdrtas.c
+++ b/drivers/watchdog/wdrtas.c
@@ -218,16 +218,14 @@ static void wdrtas_timer_keepalive(void)
*/
static int wdrtas_get_temperature(void)
{
- long result;
+ int result;
int temperature = 0;
- result = rtas_call(wdrtas_token_get_sensor_state, 2, 2,
- (void *)__pa(&temperature),
- WDRTAS_THERMAL_SENSOR, 0);
+ result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
if (result < 0)
printk(KERN_WARNING "wdrtas: reading the thermal sensor "
- "faild: %li\n", result);
+ "failed: %i\n", result);
else
temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */